From 8dec06049c4f0dcc210deec3ed8f4d9b694d963d Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Tue, 12 Sep 2017 16:00:02 -0600 Subject: [PATCH] Retire Packaging Deb project repos This commit is part of a series to retire the Packaging Deb project. Step 2 is to remove all content from the project repos, replacing it with a README notification where to find ongoing work, and how to recover the repo if needed at some future point (as in https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project). Change-Id: I74ffe4a77b923f9c0dcbe8a244dab1412e64e3f3 --- .coveragerc | 3 - .gitignore | 38 - .gitreview | 4 - .testr.conf | 5 - CONTRIBUTING.rst | 9 - LICENSE | 176 -- README | 14 + README.rst | 113 - doc/source/api_v1.rst | 103 - doc/source/cli/index.rst | 8 - doc/source/cli/ironic_client.rst | 94 - doc/source/cli/osc_plugin_cli.rst | 85 - doc/source/conf.py | 76 - doc/source/contributor/contributing.rst | 62 - doc/source/contributor/index.rst | 8 - doc/source/contributor/testing.rst | 67 - doc/source/index.rst | 29 - doc/source/user/create_command.rst | 189 -- ironicclient/__init__.py | 28 - ironicclient/client.py | 153 - ironicclient/common/__init__.py | 0 ironicclient/common/apiclient/__init__.py | 0 ironicclient/common/apiclient/base.py | 517 ---- ironicclient/common/apiclient/exceptions.py | 469 --- ironicclient/common/base.py | 249 -- ironicclient/common/cliutils.py | 296 -- ironicclient/common/filecache.py | 103 - ironicclient/common/http.py | 640 ---- ironicclient/common/i18n.py | 21 - ironicclient/common/utils.py | 393 --- ironicclient/exc.py | 71 - ironicclient/osc/__init__.py | 0 ironicclient/osc/plugin.py | 105 - ironicclient/osc/v1/__init__.py | 0 ironicclient/osc/v1/baremetal_chassis.py | 325 -- ironicclient/osc/v1/baremetal_create.py | 78 - ironicclient/osc/v1/baremetal_driver.py | 228 -- ironicclient/osc/v1/baremetal_node.py | 1609 ---------- ironicclient/osc/v1/baremetal_port.py | 496 ---- ironicclient/osc/v1/baremetal_portgroup.py | 461 --- .../osc/v1/baremetal_volume_connector.py | 362 --- .../osc/v1/baremetal_volume_target.py | 412 --- ironicclient/shell.py | 460 --- ironicclient/tests/__init__.py | 0 ironicclient/tests/functional/__init__.py | 0 ironicclient/tests/functional/base.py | 445 --- .../tests/functional/hooks/post_test_hook.sh | 49 - ironicclient/tests/functional/osc/__init__.py | 0 .../tests/functional/osc/v1/__init__.py | 0 ironicclient/tests/functional/osc/v1/base.py | 286 -- .../osc/v1/test_baremetal_chassis_basic.py | 86 - .../osc/v1/test_baremetal_node_basic.py | 199 -- .../v1/test_baremetal_node_create_negative.py | 48 - .../osc/v1/test_baremetal_node_fields.py | 137 - .../osc/v1/test_baremetal_node_negative.py | 82 - .../v1/test_baremetal_node_power_states.py | 58 - .../test_baremetal_node_provision_states.py | 81 - .../osc/v1/test_baremetal_port_basic.py | 106 - .../osc/v1/test_baremetal_portgroup_basic.py | 129 - ironicclient/tests/functional/test_chassis.py | 213 -- .../tests/functional/test_chassis_create.py | 129 - ironicclient/tests/functional/test_driver.py | 56 - .../tests/functional/test_help_msg.py | 77 - .../tests/functional/test_json_response.py | 287 -- ironicclient/tests/functional/test_node.py | 210 -- .../functional/test_node_set_power_state.py | 89 - ironicclient/tests/functional/test_port.py | 134 - .../tests/functional/test_portgroup.py | 114 - .../tests/functional/test_table_structure.py | 62 - ironicclient/tests/functional/utils.py | 37 - ironicclient/tests/unit/__init__.py | 0 ironicclient/tests/unit/common/__init__.py | 0 .../tests/unit/common/apiclient/__init__.py | 0 .../tests/unit/common/apiclient/test_base.py | 181 -- .../unit/common/apiclient/test_exceptions.py | 139 - ironicclient/tests/unit/common/test_base.py | 192 -- .../tests/unit/common/test_cliutils.py | 740 ----- .../tests/unit/common/test_filecache.py | 178 -- ironicclient/tests/unit/common/test_http.py | 788 ----- ironicclient/tests/unit/common/test_utils.py | 371 --- ironicclient/tests/unit/osc/__init__.py | 0 ironicclient/tests/unit/osc/fakes.py | 60 - ironicclient/tests/unit/osc/test_plugin.py | 110 - ironicclient/tests/unit/osc/v1/__init__.py | 0 ironicclient/tests/unit/osc/v1/fakes.py | 185 -- .../unit/osc/v1/test_baremetal_chassis.py | 591 ---- .../unit/osc/v1/test_baremetal_create.py | 78 - .../unit/osc/v1/test_baremetal_driver.py | 406 --- .../tests/unit/osc/v1/test_baremetal_node.py | 2622 ----------------- .../tests/unit/osc/v1/test_baremetal_port.py | 760 ----- .../unit/osc/v1/test_baremetal_portgroup.py | 747 ----- .../osc/v1/test_baremetal_volume_connector.py | 813 ----- .../osc/v1/test_baremetal_volume_target.py | 977 ------ ironicclient/tests/unit/test_client.py | 373 --- ironicclient/tests/unit/test_exc.py | 59 - ironicclient/tests/unit/test_import.py | 37 - ironicclient/tests/unit/test_shell.py | 398 --- ironicclient/tests/unit/utils.py | 132 - ironicclient/tests/unit/v1/__init__.py | 0 ironicclient/tests/unit/v1/test_chassis.py | 463 --- .../tests/unit/v1/test_chassis_shell.py | 391 --- ironicclient/tests/unit/v1/test_client.py | 81 - .../tests/unit/v1/test_create_resources.py | 498 ---- .../unit/v1/test_create_resources_shell.py | 31 - ironicclient/tests/unit/v1/test_driver.py | 225 -- .../tests/unit/v1/test_driver_shell.py | 194 -- ironicclient/tests/unit/v1/test_node.py | 1642 ----------- ironicclient/tests/unit/v1/test_node_shell.py | 1314 --------- ironicclient/tests/unit/v1/test_port.py | 366 --- ironicclient/tests/unit/v1/test_port_shell.py | 329 --- ironicclient/tests/unit/v1/test_portgroup.py | 440 --- .../tests/unit/v1/test_portgroup_shell.py | 298 -- .../tests/unit/v1/test_resource_fields.py | 94 - .../tests/unit/v1/test_volume_connector.py | 351 --- .../unit/v1/test_volume_connector_shell.py | 284 -- .../tests/unit/v1/test_volume_target.py | 349 --- .../tests/unit/v1/test_volume_target_shell.py | 288 -- ironicclient/v1/__init__.py | 0 ironicclient/v1/chassis.py | 170 -- ironicclient/v1/chassis_shell.py | 258 -- ironicclient/v1/client.py | 72 - ironicclient/v1/create_resources.py | 343 --- ironicclient/v1/create_resources_shell.py | 28 - ironicclient/v1/driver.py | 115 - ironicclient/v1/driver_shell.py | 150 - ironicclient/v1/node.py | 628 ---- ironicclient/v1/node_shell.py | 716 ----- ironicclient/v1/port.py | 125 - ironicclient/v1/port_shell.py | 227 -- ironicclient/v1/portgroup.py | 204 -- ironicclient/v1/portgroup_shell.py | 304 -- ironicclient/v1/resource_fields.py | 411 --- ironicclient/v1/shell.py | 48 - ironicclient/v1/utils.py | 48 - ironicclient/v1/volume_connector.py | 95 - ironicclient/v1/volume_connector_shell.py | 209 -- ironicclient/v1/volume_target.py | 96 - ironicclient/v1/volume_target_shell.py | 216 -- releasenotes/notes/.placeholder | 0 ...SHA1-hash-auth-token-f8dce46f854c002c.yaml | 4 - ...-removal-possibility-5bc0bc3a7953eaa5.yaml | 5 - .../add-create-command-3df5efbbecc33276.yaml | 10 - ...ersion-cache-timeout-dfa5f6d4af0ea1d3.yaml | 5 - .../add-json-option-0cf29be2a97e0212.yaml | 4 - ...n-integration-fields-cee7596c49722de6.yaml | 14 - ...-node-resource-class-6040d1d6c734522c.yaml | 4 - ...can-exc-construction-a776408f7ae110dc.yaml | 4 - ...d-port-internal-info-74a03ebd8b0a3dfc.yaml | 5 - ...roup-mode-properties-0a3023cf905adaef.yaml | 5 - ...d-portgroups-support-c3cf3826093ee815.yaml | 14 - ...ps-to-create-command-6d685277f7af79df.yaml | 6 - ...ttach-detach-support-e680d64e4add0fa4.yaml | 14 - ...volume-connector-api-873090474d5e41b8.yaml | 13 - ...volume-connector-cli-873090474d5e41b9.yaml | 20 - ...dd-volume-target-api-e062303f4b3b40ef.yaml | 13 - ...dd-volume-target-cli-e062303f4b3b40f0.yaml | 18 - .../add_api_versions-a59e5b6899833c33.yaml | 5 - ...dds-node-create-args-a7ace744515e5943.yaml | 6 - ...list-and-driver-show-800d96393aa17342.yaml | 16 - ...e-baremetal-node-set-c1ac57de0d481efe.yaml | 6 - ...ntinue-del-next-node-8827e67e1c41a0a5.yaml | 3 - ...-uuid-if-it-is-empty-a5471c3aa740a27d.yaml | 5 - ...r-properties-for-osc-07a99d2d4e166436.yaml | 6 - ...-vif-attach-commands-ef3a931413ddcee7.yaml | 6 - ...ature-parity-osc-cli-7606eed15f1c124f.yaml | 4 - ...ython3-compatibility-993ace45fefcba34.yaml | 5 - ...icit-version-warning-d34b99727b50d519.yaml | 7 - ...sion-warning-old-cli-fe34d423ae63544a.yaml | 7 - ...ex-error-no-endpoint-eb281187f80a9aa4.yaml | 5 - .../instance-crash-dump-d845a31e72b5a9f7.yaml | 4 - ...nic-create-files-fix-c31e40e566ff86b8.yaml | 4 - .../keystone-token-auth-661a0c0d53c1b4de.yaml | 5 - ...aremetal-api-version-a20e3099e3b97a1b.yaml | 6 - ...list-nodes-by-driver-b1e1e1018077089b.yaml | 3 - .../notes/manual-clean-09f6b49df7d2513f.yaml | 10 - .../negative-wrap-fix-4197e91b2ecfb722.yaml | 7 - ...ource-attributeerror-d0cb327abab7dcc0.yaml | 8 - ...rt-storage-interface-e93fc8d4de5d24d6.yaml | 17 - ...ore-delete-failtures-0783d33a606ed6f1.yaml | 5 - ...iver-raid-properties-159bd57058c0fc0e.yaml | 7 - .../osc-commands-1-7-d531960472a11ac2.yaml | 31 - ...osc-default-microver-172d6e69316e70c1.yaml | 4 - ...-instance-crash-dump-22634a57104561a5.yaml | 4 - .../osc-max-microver-22-dc0d91a62f03a2e6.yaml | 4 - ...sc-node-list-chassis-091d080684cdccf8.yaml | 6 - ...-list-no-maintenance-ff1cef7cfbe60fb9.yaml | 6 - ...e-list-option-driver-a2901ba6b4e1d3b5.yaml | 6 - ...-list-provisionstate-cd98dbddaad93e96.yaml | 4 - ...de-list-unassociated-60e46958a0abc3e5.yaml | 7 - ...osc-node-set-chassis-aae3413489b66b9b.yaml | 4 - .../notes/osc-plugin-9b5344aceb886cc1.yaml | 6 - ...ssis-create-show-fix-ee276d707c5a5bdf.yaml | 5 - .../notes/osc-plugin-f87e0fbb472261dd.yaml | 16 - .../notes/osc-plugin-ff0d897d8441a9e1.yaml | 36 - ...node-create-show-fix-283148c86fbccce2.yaml | 5 - ...t-target-raid-config-5d538d6253902ecb.yaml | 8 - ...osc-port-create-uuid-5da551b154540ef7.yaml | 5 - ...t-set-llc-pxeenabled-21fd8ea1982af17e.yaml | 13 - ...soft-reboot-poweroff-121b8043567f54a9.yaml | 4 - ...rsioned-endpoint-fix-08f6b7af2f47a5d6.yaml | 4 - ...rovisioning-commands-b6f5b875d573c9c8.yaml | 11 - ...ort-physical-network-6ea8860d773e473c.yaml | 5 - ...rovision-state-adopt-d07b838813cecfb1.yaml | 6 - ...provision-state-wait-e7ff919ce8e13703.yaml | 5 - .../raid_CLI_support-7e816ccd0fb31d2b.yaml | 17 - ...remove-llc-short-arg-89c7443acc6c54a4.yaml | 5 - .../remove-states-field-0242960d121a09a7.yaml | 5 - ...h-retriable-failures-91c08b9f8bdab7f3.yaml | 6 - ...nt-endpoint-override-20f1d822b4430afa.yaml | 5 - ...e-create-port-create-b213bb28bcc94743.yaml | 6 - ...soft-reboot-poweroff-e33d078a05db3894.yaml | 4 - .../start-using-reno-ccd220efa2c7022a.yaml | 3 - .../switch-requests-8304d4465a8976b1.yaml | 5 - releasenotes/source/_static/.placeholder | 0 releasenotes/source/_templates/.placeholder | 0 releasenotes/source/conf.py | 284 -- releasenotes/source/index.rst | 11 - releasenotes/source/mitaka.rst | 6 - releasenotes/source/newton.rst | 6 - releasenotes/source/ocata.rst | 6 - releasenotes/source/unreleased.rst | 5 - requirements.txt | 17 - setup.cfg | 117 - setup.py | 29 - test-requirements.txt | 19 - tools/__init__.py | 0 tools/install_venv_common.py | 210 -- tools/ironic.bash_completion | 27 - tools/run_functional.sh | 29 - tools/tox_install.sh | 55 - tools/with_venv.sh | 7 - tox.ini | 59 - 232 files changed, 14 insertions(+), 36160 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .gitignore delete mode 100644 .gitreview delete mode 100644 .testr.conf delete mode 100644 CONTRIBUTING.rst delete mode 100644 LICENSE create mode 100644 README delete mode 100644 README.rst delete mode 100644 doc/source/api_v1.rst delete mode 100644 doc/source/cli/index.rst delete mode 100644 doc/source/cli/ironic_client.rst delete mode 100644 doc/source/cli/osc_plugin_cli.rst delete mode 100644 doc/source/conf.py delete mode 100644 doc/source/contributor/contributing.rst delete mode 100644 doc/source/contributor/index.rst delete mode 100644 doc/source/contributor/testing.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/user/create_command.rst delete mode 100644 ironicclient/__init__.py delete mode 100644 ironicclient/client.py delete mode 100644 ironicclient/common/__init__.py delete mode 100644 ironicclient/common/apiclient/__init__.py delete mode 100644 ironicclient/common/apiclient/base.py delete mode 100644 ironicclient/common/apiclient/exceptions.py delete mode 100644 ironicclient/common/base.py delete mode 100644 ironicclient/common/cliutils.py delete mode 100644 ironicclient/common/filecache.py delete mode 100644 ironicclient/common/http.py delete mode 100644 ironicclient/common/i18n.py delete mode 100644 ironicclient/common/utils.py delete mode 100644 ironicclient/exc.py delete mode 100644 ironicclient/osc/__init__.py delete mode 100644 ironicclient/osc/plugin.py delete mode 100644 ironicclient/osc/v1/__init__.py delete mode 100644 ironicclient/osc/v1/baremetal_chassis.py delete mode 100644 ironicclient/osc/v1/baremetal_create.py delete mode 100644 ironicclient/osc/v1/baremetal_driver.py delete mode 100755 ironicclient/osc/v1/baremetal_node.py delete mode 100644 ironicclient/osc/v1/baremetal_port.py delete mode 100644 ironicclient/osc/v1/baremetal_portgroup.py delete mode 100644 ironicclient/osc/v1/baremetal_volume_connector.py delete mode 100644 ironicclient/osc/v1/baremetal_volume_target.py delete mode 100644 ironicclient/shell.py delete mode 100644 ironicclient/tests/__init__.py delete mode 100644 ironicclient/tests/functional/__init__.py delete mode 100644 ironicclient/tests/functional/base.py delete mode 100755 ironicclient/tests/functional/hooks/post_test_hook.sh delete mode 100644 ironicclient/tests/functional/osc/__init__.py delete mode 100644 ironicclient/tests/functional/osc/v1/__init__.py delete mode 100644 ironicclient/tests/functional/osc/v1/base.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_chassis_basic.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_node_basic.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_node_create_negative.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_node_fields.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_node_negative.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_node_power_states.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_node_provision_states.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_port_basic.py delete mode 100644 ironicclient/tests/functional/osc/v1/test_baremetal_portgroup_basic.py delete mode 100644 ironicclient/tests/functional/test_chassis.py delete mode 100644 ironicclient/tests/functional/test_chassis_create.py delete mode 100644 ironicclient/tests/functional/test_driver.py delete mode 100644 ironicclient/tests/functional/test_help_msg.py delete mode 100644 ironicclient/tests/functional/test_json_response.py delete mode 100644 ironicclient/tests/functional/test_node.py delete mode 100644 ironicclient/tests/functional/test_node_set_power_state.py delete mode 100644 ironicclient/tests/functional/test_port.py delete mode 100644 ironicclient/tests/functional/test_portgroup.py delete mode 100644 ironicclient/tests/functional/test_table_structure.py delete mode 100644 ironicclient/tests/functional/utils.py delete mode 100644 ironicclient/tests/unit/__init__.py delete mode 100644 ironicclient/tests/unit/common/__init__.py delete mode 100644 ironicclient/tests/unit/common/apiclient/__init__.py delete mode 100644 ironicclient/tests/unit/common/apiclient/test_base.py delete mode 100644 ironicclient/tests/unit/common/apiclient/test_exceptions.py delete mode 100644 ironicclient/tests/unit/common/test_base.py delete mode 100644 ironicclient/tests/unit/common/test_cliutils.py delete mode 100644 ironicclient/tests/unit/common/test_filecache.py delete mode 100644 ironicclient/tests/unit/common/test_http.py delete mode 100644 ironicclient/tests/unit/common/test_utils.py delete mode 100644 ironicclient/tests/unit/osc/__init__.py delete mode 100644 ironicclient/tests/unit/osc/fakes.py delete mode 100644 ironicclient/tests/unit/osc/test_plugin.py delete mode 100644 ironicclient/tests/unit/osc/v1/__init__.py delete mode 100644 ironicclient/tests/unit/osc/v1/fakes.py delete mode 100644 ironicclient/tests/unit/osc/v1/test_baremetal_chassis.py delete mode 100644 ironicclient/tests/unit/osc/v1/test_baremetal_create.py delete mode 100644 ironicclient/tests/unit/osc/v1/test_baremetal_driver.py delete mode 100644 ironicclient/tests/unit/osc/v1/test_baremetal_node.py delete mode 100644 ironicclient/tests/unit/osc/v1/test_baremetal_port.py delete mode 100644 ironicclient/tests/unit/osc/v1/test_baremetal_portgroup.py delete mode 100644 ironicclient/tests/unit/osc/v1/test_baremetal_volume_connector.py delete mode 100644 ironicclient/tests/unit/osc/v1/test_baremetal_volume_target.py delete mode 100644 ironicclient/tests/unit/test_client.py delete mode 100644 ironicclient/tests/unit/test_exc.py delete mode 100644 ironicclient/tests/unit/test_import.py delete mode 100644 ironicclient/tests/unit/test_shell.py delete mode 100644 ironicclient/tests/unit/utils.py delete mode 100644 ironicclient/tests/unit/v1/__init__.py delete mode 100644 ironicclient/tests/unit/v1/test_chassis.py delete mode 100644 ironicclient/tests/unit/v1/test_chassis_shell.py delete mode 100644 ironicclient/tests/unit/v1/test_client.py delete mode 100644 ironicclient/tests/unit/v1/test_create_resources.py delete mode 100644 ironicclient/tests/unit/v1/test_create_resources_shell.py delete mode 100644 ironicclient/tests/unit/v1/test_driver.py delete mode 100644 ironicclient/tests/unit/v1/test_driver_shell.py delete mode 100644 ironicclient/tests/unit/v1/test_node.py delete mode 100644 ironicclient/tests/unit/v1/test_node_shell.py delete mode 100644 ironicclient/tests/unit/v1/test_port.py delete mode 100644 ironicclient/tests/unit/v1/test_port_shell.py delete mode 100644 ironicclient/tests/unit/v1/test_portgroup.py delete mode 100644 ironicclient/tests/unit/v1/test_portgroup_shell.py delete mode 100644 ironicclient/tests/unit/v1/test_resource_fields.py delete mode 100644 ironicclient/tests/unit/v1/test_volume_connector.py delete mode 100644 ironicclient/tests/unit/v1/test_volume_connector_shell.py delete mode 100644 ironicclient/tests/unit/v1/test_volume_target.py delete mode 100644 ironicclient/tests/unit/v1/test_volume_target_shell.py delete mode 100644 ironicclient/v1/__init__.py delete mode 100644 ironicclient/v1/chassis.py delete mode 100644 ironicclient/v1/chassis_shell.py delete mode 100644 ironicclient/v1/client.py delete mode 100644 ironicclient/v1/create_resources.py delete mode 100644 ironicclient/v1/create_resources_shell.py delete mode 100644 ironicclient/v1/driver.py delete mode 100644 ironicclient/v1/driver_shell.py delete mode 100644 ironicclient/v1/node.py delete mode 100644 ironicclient/v1/node_shell.py delete mode 100644 ironicclient/v1/port.py delete mode 100644 ironicclient/v1/port_shell.py delete mode 100644 ironicclient/v1/portgroup.py delete mode 100644 ironicclient/v1/portgroup_shell.py delete mode 100644 ironicclient/v1/resource_fields.py delete mode 100644 ironicclient/v1/shell.py delete mode 100644 ironicclient/v1/utils.py delete mode 100644 ironicclient/v1/volume_connector.py delete mode 100644 ironicclient/v1/volume_connector_shell.py delete mode 100644 ironicclient/v1/volume_target.py delete mode 100644 ironicclient/v1/volume_target_shell.py delete mode 100644 releasenotes/notes/.placeholder delete mode 100644 releasenotes/notes/SHA1-hash-auth-token-f8dce46f854c002c.yaml delete mode 100644 releasenotes/notes/add-chassis_uuid-removal-possibility-5bc0bc3a7953eaa5.yaml delete mode 100644 releasenotes/notes/add-create-command-3df5efbbecc33276.yaml delete mode 100644 releasenotes/notes/add-environment-variable-to-specify-version-cache-timeout-dfa5f6d4af0ea1d3.yaml delete mode 100644 releasenotes/notes/add-json-option-0cf29be2a97e0212.yaml delete mode 100644 releasenotes/notes/add-neutron-integration-fields-cee7596c49722de6.yaml delete mode 100644 releasenotes/notes/add-node-resource-class-6040d1d6c734522c.yaml delete mode 100644 releasenotes/notes/add-pecan-exc-construction-a776408f7ae110dc.yaml delete mode 100644 releasenotes/notes/add-port-internal-info-74a03ebd8b0a3dfc.yaml delete mode 100644 releasenotes/notes/add-portgroup-mode-properties-0a3023cf905adaef.yaml delete mode 100644 releasenotes/notes/add-portgroups-support-c3cf3826093ee815.yaml delete mode 100644 releasenotes/notes/add-portgroups-to-create-command-6d685277f7af79df.yaml delete mode 100644 releasenotes/notes/add-vif-attach-detach-support-e680d64e4add0fa4.yaml delete mode 100644 releasenotes/notes/add-volume-connector-api-873090474d5e41b8.yaml delete mode 100644 releasenotes/notes/add-volume-connector-cli-873090474d5e41b9.yaml delete mode 100644 releasenotes/notes/add-volume-target-api-e062303f4b3b40ef.yaml delete mode 100644 releasenotes/notes/add-volume-target-cli-e062303f4b3b40f0.yaml delete mode 100644 releasenotes/notes/add_api_versions-a59e5b6899833c33.yaml delete mode 100644 releasenotes/notes/bug-1524745-adds-node-create-args-a7ace744515e5943.yaml delete mode 100644 releasenotes/notes/bug-1524745-extend-driver-list-and-driver-show-800d96393aa17342.yaml delete mode 100644 releasenotes/notes/bug-1524745-update-baremetal-node-set-c1ac57de0d481efe.yaml delete mode 100644 releasenotes/notes/continue-del-next-node-8827e67e1c41a0a5.yaml delete mode 100644 releasenotes/notes/display-empty-string-for-chassis-uuid-if-it-is-empty-a5471c3aa740a27d.yaml delete mode 100644 releasenotes/notes/driver-properties-for-osc-07a99d2d4e166436.yaml delete mode 100644 releasenotes/notes/extend-vif-attach-commands-ef3a931413ddcee7.yaml delete mode 100644 releasenotes/notes/feature-parity-osc-cli-7606eed15f1c124f.yaml delete mode 100644 releasenotes/notes/fix-python3-compatibility-993ace45fefcba34.yaml delete mode 100644 releasenotes/notes/implicit-version-warning-d34b99727b50d519.yaml delete mode 100644 releasenotes/notes/implicit-version-warning-old-cli-fe34d423ae63544a.yaml delete mode 100644 releasenotes/notes/index-error-no-endpoint-eb281187f80a9aa4.yaml delete mode 100644 releasenotes/notes/instance-crash-dump-d845a31e72b5a9f7.yaml delete mode 100644 releasenotes/notes/ironic-create-files-fix-c31e40e566ff86b8.yaml delete mode 100644 releasenotes/notes/keystone-token-auth-661a0c0d53c1b4de.yaml delete mode 100644 releasenotes/notes/latest-baremetal-api-version-a20e3099e3b97a1b.yaml delete mode 100644 releasenotes/notes/list-nodes-by-driver-b1e1e1018077089b.yaml delete mode 100644 releasenotes/notes/manual-clean-09f6b49df7d2513f.yaml delete mode 100644 releasenotes/notes/negative-wrap-fix-4197e91b2ecfb722.yaml delete mode 100644 releasenotes/notes/no-resource-attributeerror-d0cb327abab7dcc0.yaml delete mode 100644 releasenotes/notes/node-driver-support-storage-interface-e93fc8d4de5d24d6.yaml delete mode 100644 releasenotes/notes/not-ignore-delete-failtures-0783d33a606ed6f1.yaml delete mode 100644 releasenotes/notes/osc-baremetal-driver-raid-properties-159bd57058c0fc0e.yaml delete mode 100644 releasenotes/notes/osc-commands-1-7-d531960472a11ac2.yaml delete mode 100644 releasenotes/notes/osc-default-microver-172d6e69316e70c1.yaml delete mode 100644 releasenotes/notes/osc-instance-crash-dump-22634a57104561a5.yaml delete mode 100644 releasenotes/notes/osc-max-microver-22-dc0d91a62f03a2e6.yaml delete mode 100644 releasenotes/notes/osc-node-list-chassis-091d080684cdccf8.yaml delete mode 100644 releasenotes/notes/osc-node-list-no-maintenance-ff1cef7cfbe60fb9.yaml delete mode 100644 releasenotes/notes/osc-node-list-option-driver-a2901ba6b4e1d3b5.yaml delete mode 100644 releasenotes/notes/osc-node-list-provisionstate-cd98dbddaad93e96.yaml delete mode 100644 releasenotes/notes/osc-node-list-unassociated-60e46958a0abc3e5.yaml delete mode 100644 releasenotes/notes/osc-node-set-chassis-aae3413489b66b9b.yaml delete mode 100644 releasenotes/notes/osc-plugin-9b5344aceb886cc1.yaml delete mode 100644 releasenotes/notes/osc-plugin-chassis-create-show-fix-ee276d707c5a5bdf.yaml delete mode 100644 releasenotes/notes/osc-plugin-f87e0fbb472261dd.yaml delete mode 100644 releasenotes/notes/osc-plugin-ff0d897d8441a9e1.yaml delete mode 100644 releasenotes/notes/osc-plugin-node-create-show-fix-283148c86fbccce2.yaml delete mode 100644 releasenotes/notes/osc-plugin-node-set-target-raid-config-5d538d6253902ecb.yaml delete mode 100644 releasenotes/notes/osc-port-create-uuid-5da551b154540ef7.yaml delete mode 100644 releasenotes/notes/osc-port-set-llc-pxeenabled-21fd8ea1982af17e.yaml delete mode 100644 releasenotes/notes/osc-soft-reboot-poweroff-121b8043567f54a9.yaml delete mode 100644 releasenotes/notes/osc-versioned-endpoint-fix-08f6b7af2f47a5d6.yaml delete mode 100644 releasenotes/notes/osc-wait-option-for-provisioning-commands-b6f5b875d573c9c8.yaml delete mode 100644 releasenotes/notes/port-physical-network-6ea8860d773e473c.yaml delete mode 100644 releasenotes/notes/provision-state-adopt-d07b838813cecfb1.yaml delete mode 100644 releasenotes/notes/provision-state-wait-e7ff919ce8e13703.yaml delete mode 100644 releasenotes/notes/raid_CLI_support-7e816ccd0fb31d2b.yaml delete mode 100644 releasenotes/notes/remove-llc-short-arg-89c7443acc6c54a4.yaml delete mode 100644 releasenotes/notes/remove-states-field-0242960d121a09a7.yaml delete mode 100644 releasenotes/notes/retry-on-keystone-auth-retriable-failures-91c08b9f8bdab7f3.yaml delete mode 100644 releasenotes/notes/session-client-endpoint-override-20f1d822b4430afa.yaml delete mode 100644 releasenotes/notes/show-required-arguments-in-help-commands-of-node-create-port-create-b213bb28bcc94743.yaml delete mode 100644 releasenotes/notes/soft-reboot-poweroff-e33d078a05db3894.yaml delete mode 100644 releasenotes/notes/start-using-reno-ccd220efa2c7022a.yaml delete mode 100644 releasenotes/notes/switch-requests-8304d4465a8976b1.yaml delete mode 100644 releasenotes/source/_static/.placeholder delete mode 100644 releasenotes/source/_templates/.placeholder delete mode 100644 releasenotes/source/conf.py delete mode 100644 releasenotes/source/index.rst delete mode 100644 releasenotes/source/mitaka.rst delete mode 100644 releasenotes/source/newton.rst delete mode 100644 releasenotes/source/ocata.rst delete mode 100644 releasenotes/source/unreleased.rst delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tools/__init__.py delete mode 100644 tools/install_venv_common.py delete mode 100644 tools/ironic.bash_completion delete mode 100755 tools/run_functional.sh delete mode 100755 tools/tox_install.sh delete mode 100755 tools/with_venv.sh delete mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index f45d51a..0000000 --- a/.coveragerc +++ /dev/null @@ -1,3 +0,0 @@ -[report] -include = ironicclient/* -omit = ironicclient/tests/functional/* diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6a6b9a9..0000000 --- a/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -# Compiled files -*.py[co] -*.a -*.o -*.so - -# Sphinx -_build -doc/source/api/ - -# Release notes -releasenotes/build - -# Packages/installer info -*.egg -*.egg-info -dist -build -eggs -parts -var -sdist -develop-eggs -.installed.cfg - -# Other -*.DS_Store -.testrepository -.tox -.idea -.venv -.*.swp -.coverage -cover -AUTHORS -ChangeLog -*.sqlite -test.conf diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 1ed2696..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/python-ironicclient.git diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 984a597..0000000 --- a/.testr.conf +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} ${PYTHON:-python} -m subunit.run discover -t ./ ${TESTS_DIR:-./ironicclient/tests/unit} $LISTOPT $IDOPTION - -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index fa92b9d..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,9 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps documented at: - - http://docs.openstack.org/infra/manual/developers.html - -More information on contributing can be found within the project -documentation: - - http://docs.openstack.org/developer/python-ironicclient/contributing.html diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a..0000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - diff --git a/README b/README new file mode 100644 index 0000000..8fcd2b2 --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +For ongoing work on maintaining OpenStack packages in the Debian +distribution, please see the Debian OpenStack packaging team at +https://wiki.debian.org/OpenStack/. + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/README.rst b/README.rst deleted file mode 100644 index e2eb0d3..0000000 --- a/README.rst +++ /dev/null @@ -1,113 +0,0 @@ -======================== -Team and repository tags -======================== - -.. image:: https://governance.openstack.org/tc/badges/python-ironicclient.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html - -.. Change things from this point on - -Python bindings for the Ironic API -================================== - -This is a client for the OpenStack `Ironic -`_ API. It provides a Python API (the -``ironicclient`` module) and a command-line interface (``ironic``). - -Development takes place via the usual OpenStack processes as outlined in the -`developer guide `_. The master -repository is on `git.openstack.org -`_. - -``python-ironicclient`` is licensed under the Apache License like the rest -of OpenStack. - - -.. contents:: Contents: - :local: - -Python API ----------- - -Quick-start Example:: - >>> from ironicclient import client - >>> - >>> kwargs = {'os_auth_token': '3bcc3d3a03f44e3d8377f9247b0ad155', - >>> 'ironic_url': 'http://ironic.example.org:6385/'} - >>> ironic = client.get_client(1, **kwargs) - - -Command-line API ----------------- - -This package will install the ``ironic`` command line interface that you -can use to interact with the ``ironic`` API. - -In order to use the ``ironic`` CLI you'll need to provide your OpenStack -tenant, username, password and authentication endpoint. You can do this with -the ``--os-tenant-name``, ``--os-username``, ``--os-password`` and -``--os-auth-url`` parameters, though it may be easier to set them -as environment variables:: - - $ export OS_PROJECT_NAME=project - $ export OS_USERNAME=user - $ export OS_PASSWORD=pass - $ export OS_AUTH_URL=http://auth.example.com:5000/v2.0 - -To use a specific Ironic API endpoint:: - - $ export IRONIC_URL=http://ironic.example.com:6385 - -An example of creating a basic node with the pxe_ipmitool driver:: - - $ ironic node-create -d pxe_ipmitool - -An example of creating a port on a node:: - - $ ironic port-create -a AA:BB:CC:DD:EE:FF -n nodeUUID - -An example of updating driver properties for a node:: - - $ ironic node-update nodeUUID add driver_info/ipmi_address= - $ ironic node-update nodeUUID add driver_info/ipmi_username= - $ ironic node-update nodeUUID add driver_info/ipmi_password= - - -For more information about the ``ironic`` command and the subcommands -available, run:: - - $ ironic help - -OpenStackClient Baremetal Plugin --------------------------------- - -In order to use Baremetal Plugin the OpenStackClient should be installed:: - - # pip install python-openstackclient - -An example of creating a basic node with the agent_ipmitool driver:: - - $ openstack baremetal node create --driver agent_ipmitool - -An example of creating a port on a node:: - - $ openstack baremetal port create --node AA:BB:CC:DD:EE:FF - -An example of updating driver properties for a node:: - - $ openstack baremetal node set --driver-info ipmi_address= - -For more information about the ``openstack baremetal`` command and -the subcommands available, run:: - - $ openstack help baremetal - -* License: Apache License, Version 2.0 -* Documentation: https://docs.openstack.org/python-ironicclient/latest/ -* Source: https://git.openstack.org/cgit/openstack/python-ironicclient -* Bugs: https://bugs.launchpad.net/python-ironicclient - -Change logs with information about specific versions (or tags) are -available at: - - ``_. diff --git a/doc/source/api_v1.rst b/doc/source/api_v1.rst deleted file mode 100644 index cd5c866..0000000 --- a/doc/source/api_v1.rst +++ /dev/null @@ -1,103 +0,0 @@ -.. _api_v1: - -======================= -ironicclient Python API -======================= - -The ironicclient python API lets you access ironic, the OpenStack -Bare Metal Provisioning Service. - -For example, to manipulate nodes, you interact with an -`ironicclient.v1.node`_ object. -You obtain access to nodes via attributes of the -`ironicclient.v1.client.Client`_ object. - -Usage -===== - -Get a Client object -------------------- -First, create an `ironicclient.v1.client.Client`_ instance by passing your -credentials to `ironicclient.client.get_client()`_. By default, the -Bare Metal Provisioning system is configured so that only administrators -(users with 'admin' role) have access. - -.. note:: - Explicit instantiation of `ironicclient.v1.client.Client`_ may cause - errors since it doesn't verify provided arguments, using - `ironicclient.client.get_client()` is preferred way to get client object. - -There are two different sets of credentials that can be used:: - - * ironic endpoint and auth token - * Identity Service (keystone) credentials - -Using ironic endpoint and auth token -.................................... - -An auth token and the ironic endpoint can be used to authenticate:: - - * os_auth_token: authentication token (from Identity Service) - * ironic_url: ironic API endpoint, eg http://ironic.example.org:6385/v1 - -To create the client, you can use the API like so:: - - >>> from ironicclient import client - >>> - >>> kwargs = {'os_auth_token': '3bcc3d3a03f44e3d8377f9247b0ad155', - >>> 'ironic_url': 'http://ironic.example.org:6385/'} - >>> ironic = client.get_client(1, **kwargs) - -Using Identity Service (keystone) credentials -............................................. - -These Identity Service credentials can be used to authenticate:: - - * os_username: name of user - * os_password: user's password - * os_auth_url: Identity Service endpoint for authorization - * insecure: Boolean. If True, does not perform X.509 certificate - validation when establishing SSL connection with identity - service. default: False (optional) - * os_tenant_{name|id}: name or ID of tenant - -To create a client, you can use the API like so:: - - >>> from ironicclient import client - >>> - >>> kwargs = {'os_username': 'name', - >>> 'os_password': 'password', - >>> 'os_auth_url': 'http://keystone.example.org:5000/', - >>> 'os_project_name': 'project'} - >>> ironic = client.get_client(1, **kwargs) - -Perform ironic operations -------------------------- - -Once you have an ironic `Client`_, you can perform various tasks:: - - >>> ironic.driver.list() # list of drivers - >>> ironic.node.list() # list of nodes - >>> ironic.node.get(node_uuid) # information about a particular node - -When the `Client`_ needs to propagate an exception, it will usually -raise an instance subclassed from -`ironicclient.exc.BaseException`_ or `ironicclient.exc.ClientException`_. - -Refer to the modules themselves, for more details. - -ironicclient Modules -==================== - -.. toctree:: - :maxdepth: 1 - - modules - - -.. _ironicclient.v1.node: api/ironicclient.v1.node.html#ironicclient.v1.node.Node -.. _ironicclient.v1.client.Client: api/ironicclient.v1.client.html#ironicclient.v1.client.Client -.. _Client: api/ironicclient.v1.client.html#ironicclient.v1.client.Client -.. _ironicclient.client.get_client(): api/ironicclient.client.html#ironicclient.client.get_client -.. _ironicclient.exc.BaseException: api/ironicclient.exc.html#ironicclient.exc.BaseException -.. _ironicclient.exc.ClientException: api/ironicclient.exc.html#ironicclient.exc.ClientException diff --git a/doc/source/cli/index.rst b/doc/source/cli/index.rst deleted file mode 100644 index 251e71c..0000000 --- a/doc/source/cli/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -====================================== -python-ironicclient User Documentation -====================================== - -.. toctree:: - - ironic_client - osc_plugin_cli diff --git a/doc/source/cli/ironic_client.rst b/doc/source/cli/ironic_client.rst deleted file mode 100644 index 92c02b0..0000000 --- a/doc/source/cli/ironic_client.rst +++ /dev/null @@ -1,94 +0,0 @@ -========================================== -Ironic Client Command-Line Interface (CLI) -========================================== - -.. program:: ironic -.. highlight:: bash - -SYNOPSIS -======== - -:program:`ironic` [options] [command-options] - -:program:`ironic help` - -:program:`ironic help` - - -DESCRIPTION -=========== - -The :program:`ironic` command-line interface (CLI) interacts with the -OpenStack Bare Metal Service (Ironic). - -In order to use the CLI, you must provide your OpenStack username, password, -project (historically called tenant), and auth endpoint. You can use -configuration options :option:`--os-username`, :option:`--os-password`, -:option:`--os-tenant-id` (or :option:`--os-tenant-name`), -and :option:`--os-auth-url`, or set the corresponding -environment variables:: - - $ export OS_USERNAME=user - $ export OS_PASSWORD=password - $ export OS_PROJECT_ID=b363706f891f48019483f8bd6503c54b # or OS_PROJECT_NAME - $ export OS_PROJECT_NAME=project # or OS_PROJECT_ID - $ export OS_AUTH_URL=http://auth.example.com:5000/v2.0 - -The command-line tool will attempt to reauthenticate using the provided -credentials for every request. You can override this behavior by manually -supplying an auth token using :option:`--ironic-url` and -:option:`--os-auth-token`, or by setting the corresponding environment -variables:: - - $ export IRONIC_URL=http://ironic.example.org:6385/ - $ export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155 - -Since Keystone can return multiple regions in the Service Catalog, you can -specify the one you want with :option:`--os-region-name` or set the following -environment variable. (It defaults to the first in the list returned.) -:: - - export OS_REGION_NAME=region - -Ironic CLI supports bash completion. The command-line tool can automatically -fill partially typed commands. To use this feature, source the below file -(available at -https://git.openstack.org/cgit/openstack/python-ironicclient/tree/tools/ironic.bash_completion) -to your terminal and then bash completion should work:: - - $ source ironic.bash_completion - -To avoid doing this every time, add this to your ``.bashrc`` or copy the -ironic.bash_completion file to the default bash completion scripts directory -on your linux distribution. - -OPTIONS -======= - -To get a list of available (sub)commands and options, run:: - - $ ironic help - -To get usage and options of a command, run:: - - $ ironic help - - -EXAMPLES -======== - -Get information about the node-create command:: - - $ ironic help node-create - -Get a list of available drivers:: - - $ ironic driver-list - -Enroll a node with "fake" deploy driver and "ipmitool" power driver:: - - $ ironic node-create -d fake_ipmitool -i ipmi_address=1.2.3.4 - -Get a list of nodes:: - - $ ironic node-list diff --git a/doc/source/cli/osc_plugin_cli.rst b/doc/source/cli/osc_plugin_cli.rst deleted file mode 100644 index 924d3e5..0000000 --- a/doc/source/cli/osc_plugin_cli.rst +++ /dev/null @@ -1,85 +0,0 @@ -============================================= -OpenStack Client Command-Line Interface (CLI) -============================================= - -.. program:: openstack baremetal -.. highlight:: bash - -Synopsis -======== - -:program:`openstack [options] baremetal` [command-options] - -:program:`openstack help baremetal` - - -Description -=========== - -The OpenStack Client plugin interacts with the Bare Metal service -through the ``openstack baremetal`` command line interface (CLI). - -To use ``openstack`` CLI, the OpenStackClient should be installed:: - - # pip install python-openstackclient - -To use the CLI, you must provide your OpenStack username, password, -project, and auth endpoint. You can use configuration options -:option:`--os-username`, :option:`--os-password`, :option:`--os-project-id` -(or :option:`--os-project-name`), and :option:`--os-auth-url`, -or set the corresponding environment variables:: - - $ export OS_USERNAME=user - $ export OS_PASSWORD=password - $ export OS_PROJECT_NAME=project # or OS_PROJECT_ID - $ export OS_PROJECT_DOMAIN_ID=default - $ export OS_USER_DOMAIN_ID=default - $ export OS_IDENTITY_API_VERSION=3 - $ export OS_AUTH_URL=http://auth.example.com:5000/identity - -This CLI is provided by python-openstackclient and osc-lib projects: - -* https://git.openstack.org/openstack/python-openstackclient -* https://git.openstack.org/openstack/osc-lib - - -Getting help -============ - -To get a list of available (sub)commands and options, run:: - - $ openstack help baremetal - -To get usage and options of a command, run:: - - $ openstack help baremetal - - -Examples -======== - -Get information about the openstack baremetal node create command:: - - $ openstack help baremetal node create - -Get a list of available drivers:: - - $ openstack baremetal driver list - -Enroll a node with "agent_ipmitool" driver:: - - $ openstack baremetal node create --driver agent_ipmitool --driver-info ipmi_address=1.2.3.4 - -Get a list of nodes:: - - $ openstack baremetal node list - -The baremetal API version can be specified via: - -* environment variable OS_BAREMETAL_API_VERSION:: - - $ export OS_BAREMETAL_API_VERSION=1.25 - -* or optional command line argument --os-baremetal-api-version:: - - $ openstack baremetal port group list --os-baremetal-api-version 1.25 diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 26cedab..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,76 +0,0 @@ -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.viewcode', - 'openstackdocstheme', - ] - -# openstackdocstheme options -repository_name = 'openstack/python-ironicclient' -bug_project = 'python-ironicclient' -bug_tag = '' - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'python-ironicclient' -copyright = u'OpenStack Foundation' - -# A list of ignored prefixes for module index sorting. -modindex_common_prefix = ['ironicclient.'] - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of glob-style patterns that should be excluded when looking for -# source files. They are matched against the source file names relative to the -# source directory, using slashes as directory separators on all platforms. -exclude_patterns = ['api/ironicclient.tests.functional.*'] - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -#html_theme_path = ["."] -#html_theme = '_theme' -#html_static_path = ['_static'] -html_theme = 'openstackdocs' - -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ( - 'index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack LLC', - 'manual' - ), -] diff --git a/doc/source/contributor/contributing.rst b/doc/source/contributor/contributing.rst deleted file mode 100644 index a0dd201..0000000 --- a/doc/source/contributor/contributing.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. _contributing: - -=================================== -Contributing to python-ironicclient -=================================== - -If you're interested in contributing to the python-ironicclient project, -the following will help get you started. - -#openstack-ironic on Freenode IRC Network ------------------------------------------ -There is a very active chat channel at irc://freenode.net/#openstack-ironic. -This is usually the best place to ask questions and find your way around. -IRC stands for Internet Relay Chat and it is a way to chat online in real -time. You can ask a question and come back later to read the answer in the -log files. Logs for the #openstack-ironic IRC channel are stored at -http://eavesdrop.openstack.org/irclogs/%23openstack-ironic/. - -Contributor License Agreement ------------------------------ - -.. index:: - single: license; agreement - -In order to contribute to the python-ironicclient project, you need to have -signed OpenStack's contributor's agreement. - -.. seealso:: - - * https://docs.openstack.org/infra/manual/developers.html - * https://wiki.openstack.org/wiki/CLA - -LaunchPad Project ------------------ - -Most of the tools used for OpenStack depend on a launchpad.net ID for -authentication. After signing up for a launchpad account, join the -"openstack" team to have access to the mailing list and receive -notifications of important events. - -.. seealso:: - - * https://launchpad.net - * https://launchpad.net/python-ironicclient - * https://launchpad.net/~openstack - - -Project Hosting Details ------------------------ - -Bug tracker - https://launchpad.net/python-ironicclient - -Mailing list (prefix subjects with ``[ironic]`` for faster responses) - http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev - -Code Hosting - https://git.openstack.org/cgit/openstack/python-ironicclient - -Code Review - https://review.openstack.org/#/q/status:open+project:openstack/python-ironicclient,n,z - diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst deleted file mode 100644 index e0c9823..0000000 --- a/doc/source/contributor/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -============================================= -python-ironicclient Contributor Documentation -============================================= - -.. toctree:: - - contributing - testing diff --git a/doc/source/contributor/testing.rst b/doc/source/contributor/testing.rst deleted file mode 100644 index 97a6491..0000000 --- a/doc/source/contributor/testing.rst +++ /dev/null @@ -1,67 +0,0 @@ -.. _testing: - -======= -Testing -======= - -Python Guideline Enforcement -............................ - -All code has to pass the pep8 style guideline to merge into OpenStack, to -validate the code against these guidelines you can run:: - - $ tox -e pep8 - -Unit Testing -............ - -It is strongly encouraged to run the unit tests locally under one or more -test environments prior to submitting a patch. To run all the recommended -environments sequentially and pep8 style guideline run:: - - $ tox - -You can also selectively pick specific test environments by listing your -chosen environments after a -e flag:: - - $ tox -e py35,py27,pep8,pypy - -.. note:: - Tox sets up virtual environment and installs all necessary dependencies. - Sharing the environment with devstack testing is not recommended due to - conflicting configuration with system dependencies. - -Functional Testing -.................. - -Functional testing assumes the existence of the script run_functional.sh in the -python-ironicclient/tools directory. The script run_functional.sh generates -test.conf file. To run functional tests just run ./run_functional.sh. - -Also, the test.conf file could be created manually or generated from -environment variables. It assumes the existence of an openstack -cloud installation along with admin credentials. The test.conf file lives in -ironicclient/tests/functional/ directory. To run functional tests in that way -create test.conf manually and run:: - - $ tox -e functional - -An example test.conf file:: - - [functional] - api_version = 1 - os_auth_url=http://192.168.0.2:5000/v2.0/ - os_username=admin - os_password=admin - os_project_name=admin - -If you are testing ironic in standalone mode, only the parameters -'auth_strategy', 'os_auth_token' and 'ironic_url' are required; -all others will be ignored. - -An example test.conf file for standalone host:: - - [functional] - auth_strategy = noauth - os_auth_token = fake - ironic_url = http://10.0.0.2:6385 diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 16766d7..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,29 +0,0 @@ -=========================================== -Python Bindings to the OpenStack Ironic API -=========================================== - -This is a client for OpenStack `Ironic`_ API. There's a Python API -(the `ironicclient` modules), and a command-line interface (installed as -`ironic`). - -Contents -======== - -.. toctree:: - :maxdepth: 2 - - api_v1 - cli/index - user/create_command - contributor/index - Release Notes - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - - -.. _Ironic: https://wiki.openstack.org/wiki/Ironic diff --git a/doc/source/user/create_command.rst b/doc/source/user/create_command.rst deleted file mode 100644 index ec966c9..0000000 --- a/doc/source/user/create_command.rst +++ /dev/null @@ -1,189 +0,0 @@ -=================================================== -Creating the Bare Metal service resources from file -=================================================== - -It is possible to create a set of resources using their descriptions in JSON -or YAML format. It can be done in one of three ways: - -1. Using ironic CLI's ``ironic create`` command:: - - $ ironic help create - usage: ironic create [ ...] - - Create baremetal resources (chassis, nodes, port groups and ports). The - resources may be described in one or more JSON or YAML files. If any file - cannot be validated, no resources are created. An attempt is made to - create all the resources; those that could not be created are skipped - (with a corresponding error message). - - Positional arguments: - File (.yaml or .json) containing descriptions of the resources - to create. Can be specified multiple times. - -2. Using openstackclient plugin command ``openstack baremetal create``:: - - $ openstack -h baremetal create - usage: openstack [-h] [-f {json,shell,table,value,yaml}] [-c COLUMN] - [--max-width ] [--noindent] [--prefix PREFIX] - [--chassis-uuid ] [--driver-info ] - [--property ] [--extra ] - [--uuid ] [--name ] - [--network-interface ] - [--resource-class ] [--driver ] - [ [ ...]] - - Create resources from files or Register a new node (DEPRECATED). Create - resources from files (by only specifying the files) or register a new - node by specifying one or more optional arguments (DEPRECATED, use - 'openstack baremetal node create' instead). - - positional arguments: - File (.yaml or .json) containing descriptions of - the resources to create. Can be specified - multiple times. If you want to create resources, - only specify the files. Do not specify any of - the optional arguments. - - .. note:: - If the ``--driver`` argument is passed in, the behaviour of the command - is the same as ``openstack baremetal node create``, and positional - arguments are ignored. If it is not provided, the command does resource - creation from file(s), and only positional arguments will be taken into - account. - -3. Programmatically using the Python API: - - .. autofunction:: ironicclient.v1.create_resources.create_resources - :noindex: - -File containing Resource Descriptions -===================================== - -The resources to be created can be described either in JSON or YAML. A file -ending with ``.json`` is assumed to contain valid JSON, and a file ending with -``.yaml`` is assumed to contain valid YAML. Specifying a file with any other -extension leads to an error. - -The resources that can be created are chassis, nodes, port groups and ports. -A chassis can contain nodes (and resources of nodes) definitions nested under -``"nodes"`` key. A node can contain port groups definitions nested under -``"portgroups"``, and ports definitions under ``"ports"`` keys. Ports can be -also nested under port groups in ``"ports"`` key. - -The schema used to validate the supplied data is the following:: - - { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Schema for ironic resources file", - "type": "object", - "properties": { - "chassis": { - "type": "array", - "items": { - "type": "object" - } - }, - "nodes": { - "type": "array", - "items": { - "type": "object" - } - } - }, - "additionalProperties": False - } - -More detailed description of the creation process can be seen in the following -sections. - -Examples -======== - -Here is an example of the JSON file that can be passed to the ``create`` -command:: - - { - "chassis": [ - { - "description": "chassis 3 in row 23", - "nodes": [ - { - "name": "node-3", - "driver": "agent_ipmitool", - "portgroups": [ - { - "name": "switch.cz7882.ports.1-2", - "ports": [ - { - "address": "ff:00:00:00:00:00" - }, - { - "address": "ff:00:00:00:00:01" - } - ] - } - ], - "ports": [ - { - "address": "00:00:00:00:00:02" - }, - { - "address": "00:00:00:00:00:03" - } - ] - }, - { - "name": "node-4", - "driver": "agent_ipmitool", - "ports": [ - { - "address": "00:00:00:00:00:04" - }, - { - "address": "00:00:00:00:00:01" - } - ] - } - ] - } - ], - "nodes": [ - { - "name": "node-5", - "driver": "pxe_ipmitool", - "chassis_uuid": "74d93e6e-7384-4994-a614-fd7b399b0785", - "ports": [ - { - "address": "00:00:00:00:00:00" - } - ] - }, - { - "name": "node-6", - "driver": "pxe_ipmitool" - } - ] - } - -Creation Process -================ - -#. The client deserializes the files' contents and validates that the top-level - dictionary in each of them contains only "chassis" and/or "nodes" keys, - and their values are lists. The creation process is aborted if any failure - is encountered in this stage. The rest of the validation is done by the - ironic-api service. - -#. Each resource is created via issuing a POST request (with the resource's - dictionary representation in the body) to the ironic-api service. In the - case of nested resources (``"nodes"`` key inside chassis, ``"portgroups"`` - key inside nodes, ``"ports"`` key inside nodes or portgroups), the top-level - resource is created first, followed by the sub-resources. For example, if a - chassis contains a list of nodes, the chassis will be created first followed - by the creation of each node. The same is true for ports and port groups - described within nodes. - -#. If a resource could not be created, it does not stop the entire process. - Any sub-resources of the failed resource will not be created, but otherwise, - the rest of the resources will be created if possible. Any failed resources - will be mentioned in the response. diff --git a/ironicclient/__init__.py b/ironicclient/__init__.py deleted file mode 100644 index c78865e..0000000 --- a/ironicclient/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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 pbr.version - -from ironicclient import client -from ironicclient import exc as exceptions - - -__version__ = pbr.version.VersionInfo('python-ironicclient').version_string() - -__all__ = ( - 'client', - 'exc', - 'exceptions', -) diff --git a/ironicclient/client.py b/ironicclient/client.py deleted file mode 100644 index 74c5ae8..0000000 --- a/ironicclient/client.py +++ /dev/null @@ -1,153 +0,0 @@ -# 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 keystoneauth1 import loading as kaloading -from oslo_utils import importutils - -from ironicclient.common.i18n import _ -from ironicclient import exc - - -def get_client(api_version, os_auth_token=None, ironic_url=None, - os_username=None, os_password=None, os_auth_url=None, - os_project_id=None, os_project_name=None, os_tenant_id=None, - os_tenant_name=None, os_region_name=None, - os_user_domain_id=None, os_user_domain_name=None, - os_project_domain_id=None, os_project_domain_name=None, - os_service_type=None, os_endpoint_type=None, - insecure=None, timeout=None, os_cacert=None, ca_file=None, - os_cert=None, cert_file=None, os_key=None, key_file=None, - os_ironic_api_version=None, max_retries=None, - retry_interval=None, session=None, **ignored_kwargs): - """Get an authenticated client, based on the credentials. - - :param api_version: the API version to use. Valid value: '1'. - :param os_auth_token: pre-existing token to re-use - :param ironic_url: ironic API endpoint - :param os_username: name of a user - :param os_password: user's password - :param os_auth_url: endpoint to authenticate against - :param os_tenant_name: name of a tenant (deprecated in favour of - os_project_name) - :param os_tenant_id: ID of a tenant (deprecated in favour of - os_project_id) - :param os_project_name: name of a project - :param os_project_id: ID of a project - :param os_region_name: name of a keystone region - :param os_user_domain_name: name of a domain the user belongs to - :param os_user_domain_id: ID of a domain the user belongs to - :param os_project_domain_name: name of a domain the project belongs to - :param os_project_domain_id: ID of a domain the project belongs to - :param os_service_type: the type of service to lookup the endpoint for - :param os_endpoint_type: the type (exposure) of the endpoint - :param insecure: allow insecure SSL (no cert verification) - :param timeout: allows customization of the timeout for client HTTP - requests - :param os_cacert: path to cacert file - :param ca_file: path to cacert file, deprecated in favour of os_cacert - :param os_cert: path to cert file - :param cert_file: path to cert file, deprecated in favour of os_cert - :param os_key: path to key file - :param key_file: path to key file, deprecated in favour of os_key - :param os_ironic_api_version: ironic API version to use - :param max_retries: Maximum number of retries in case of conflict error - :param retry_interval: Amount of time (in seconds) between retries in case - of conflict error - :param session: Keystone session to use - :param ignored_kwargs: all the other params that are passed. Left for - backwards compatibility. They are ignored. - """ - os_service_type = os_service_type or 'baremetal' - os_endpoint_type = os_endpoint_type or 'publicURL' - project_id = (os_project_id or os_tenant_id) - project_name = (os_project_name or os_tenant_name) - kwargs = { - 'os_ironic_api_version': os_ironic_api_version, - 'max_retries': max_retries, - 'retry_interval': retry_interval, - } - endpoint = ironic_url - cacert = os_cacert or ca_file - cert = os_cert or cert_file - key = os_key or key_file - if os_auth_token and endpoint: - kwargs.update({ - 'token': os_auth_token, - 'insecure': insecure, - 'ca_file': cacert, - 'cert_file': cert, - 'key_file': key, - 'timeout': timeout, - }) - elif os_auth_url: - auth_type = 'password' - auth_kwargs = { - 'auth_url': os_auth_url, - 'project_id': project_id, - 'project_name': project_name, - 'user_domain_id': os_user_domain_id, - 'user_domain_name': os_user_domain_name, - 'project_domain_id': os_project_domain_id, - 'project_domain_name': os_project_domain_name, - } - if os_username and os_password: - auth_kwargs.update({ - 'username': os_username, - 'password': os_password, - }) - elif os_auth_token: - auth_type = 'token' - auth_kwargs.update({ - 'token': os_auth_token, - }) - # Create new session only if it was not passed in - if not session: - loader = kaloading.get_plugin_loader(auth_type) - auth_plugin = loader.load_from_options(**auth_kwargs) - # Let keystoneauth do the necessary parameter conversions - session = kaloading.session.Session().load_from_options( - auth=auth_plugin, insecure=insecure, cacert=cacert, - cert=cert, key=key, timeout=timeout, - ) - - exception_msg = _('Must provide Keystone credentials or user-defined ' - 'endpoint and token') - if not endpoint: - if session: - try: - # Pass the endpoint, it will be used to get hostname - # and port that will be used for API version caching. It will - # be also set as endpoint_override. - endpoint = session.get_endpoint( - service_type=os_service_type, - interface=os_endpoint_type, - region_name=os_region_name - ) - except Exception as e: - raise exc.AmbiguousAuthSystem( - _('%(message)s, error was: %(error)s') % - {'message': exception_msg, 'error': e}) - else: - # Neither session, nor valid auth parameters provided - raise exc.AmbiguousAuthSystem(exception_msg) - - # Always pass the session - kwargs['session'] = session - - return Client(api_version, endpoint, **kwargs) - - -def Client(version, *args, **kwargs): - module = importutils.import_versioned_module('ironicclient', - version, 'client') - client_class = getattr(module, 'Client') - return client_class(*args, **kwargs) diff --git a/ironicclient/common/__init__.py b/ironicclient/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/common/apiclient/__init__.py b/ironicclient/common/apiclient/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/common/apiclient/base.py b/ironicclient/common/apiclient/base.py deleted file mode 100644 index fcf536d..0000000 --- a/ironicclient/common/apiclient/base.py +++ /dev/null @@ -1,517 +0,0 @@ -# Copyright 2010 Jacob Kaplan-Moss -# Copyright 2011 OpenStack Foundation -# Copyright 2012 Grid Dynamics -# Copyright 2013 OpenStack Foundation -# 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. - -""" -Base utilities to build API operation managers and objects on top of. -""" - - -# E1102: %s is not callable -# pylint: disable=E1102 - -import abc -import copy - -from oslo_utils import strutils -import six -from six.moves import http_client -from six.moves.urllib import parse - -from ironicclient.common.apiclient import exceptions -from ironicclient.common.i18n import _ - - -def getid(obj): - """Return id if argument is a Resource. - - Abstracts the common pattern of allowing both an object or an object's ID - (UUID) as a parameter when dealing with relationships. - """ - try: - if obj.uuid: - return obj.uuid - except AttributeError: - pass - try: - return obj.id - except AttributeError: - return obj - - -# TODO(aababilov): call run_hooks() in HookableMixin's child classes -class HookableMixin(object): - """Mixin so classes can register and run hooks.""" - _hooks_map = {} - - @classmethod - def add_hook(cls, hook_type, hook_func): - """Add a new hook of specified type. - - :param cls: class that registers hooks - :param hook_type: hook type, e.g., '__pre_parse_args__' - :param hook_func: hook function - """ - if hook_type not in cls._hooks_map: - cls._hooks_map[hook_type] = [] - - cls._hooks_map[hook_type].append(hook_func) - - @classmethod - def run_hooks(cls, hook_type, *args, **kwargs): - """Run all hooks of specified type. - - :param cls: class that registers hooks - :param hook_type: hook type, e.g., '__pre_parse_args__' - :param args: args to be passed to every hook function - :param kwargs: kwargs to be passed to every hook function - """ - hook_funcs = cls._hooks_map.get(hook_type) or [] - for hook_func in hook_funcs: - hook_func(*args, **kwargs) - - -class BaseManager(HookableMixin): - """Basic manager type providing common operations. - - Managers interact with a particular type of API (servers, flavors, images, - etc.) and provide CRUD operations for them. - """ - resource_class = None - - def __init__(self, client): - """Initializes BaseManager with `client`. - - :param client: instance of BaseClient descendant for HTTP requests - """ - super(BaseManager, self).__init__() - self.client = client - - def _list(self, url, response_key=None, obj_class=None, json=None): - """List the collection. - - :param url: a partial URL, e.g., '/servers' - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers'. If response_key is None - all response body - will be used. - :param obj_class: class for constructing the returned objects - (self.resource_class will be used by default) - :param json: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - """ - if json: - body = self.client.post(url, json=json).json() - else: - body = self.client.get(url).json() - - if obj_class is None: - obj_class = self.resource_class - - data = body[response_key] if response_key is not None else body - # NOTE(ja): keystone returns values as list as {'values': [ ... ]} - # unlike other services which just return the list... - try: - data = data['values'] - except (KeyError, TypeError): - pass - - return [obj_class(self, res, loaded=True) for res in data if res] - - def _get(self, url, response_key=None): - """Get an object from collection. - - :param url: a partial URL, e.g., '/servers' - :param response_key: the key to be looked up in response dictionary, - e.g., 'server'. If response_key is None - all response body - will be used. - """ - body = self.client.get(url).json() - data = body[response_key] if response_key is not None else body - return self.resource_class(self, data, loaded=True) - - def _head(self, url): - """Retrieve request headers for an object. - - :param url: a partial URL, e.g., '/servers' - """ - resp = self.client.head(url) - return resp.status_code == http_client.NO_CONTENT - - def _post(self, url, json, response_key=None, return_raw=False): - """Create an object. - - :param url: a partial URL, e.g., '/servers' - :param json: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'server'. If response_key is None - all response body - will be used. - :param return_raw: flag to force returning raw JSON instead of - Python object of self.resource_class - """ - body = self.client.post(url, json=json).json() - data = body[response_key] if response_key is not None else body - if return_raw: - return data - return self.resource_class(self, data) - - def _put(self, url, json=None, response_key=None): - """Update an object with PUT method. - - :param url: a partial URL, e.g., '/servers' - :param json: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers'. If response_key is None - all response body - will be used. - """ - resp = self.client.put(url, json=json) - # PUT requests may not return a body - if resp.content: - body = resp.json() - if response_key is not None: - return self.resource_class(self, body[response_key]) - else: - return self.resource_class(self, body) - - def _patch(self, url, json=None, response_key=None): - """Update an object with PATCH method. - - :param url: a partial URL, e.g., '/servers' - :param json: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers'. If response_key is None - all response body - will be used. - """ - body = self.client.patch(url, json=json).json() - if response_key is not None: - return self.resource_class(self, body[response_key]) - else: - return self.resource_class(self, body) - - def _delete(self, url): - """Delete an object. - - :param url: a partial URL, e.g., '/servers/my-server' - """ - return self.client.delete(url) - - -@six.add_metaclass(abc.ABCMeta) -class ManagerWithFind(BaseManager): - """Manager with additional `find()`/`findall()` methods.""" - - @abc.abstractmethod - def list(self): - pass - - def find(self, **kwargs): - """Find a single item with attributes matching ``**kwargs``. - - This isn't very efficient: it loads the entire list then filters on - the Python side. - """ - matches = self.findall(**kwargs) - num_matches = len(matches) - if num_matches == 0: - msg = _("No %(name)s matching %(args)s.") % { - 'name': self.resource_class.__name__, - 'args': kwargs - } - raise exceptions.NotFound(msg) - elif num_matches > 1: - raise exceptions.NoUniqueMatch() - else: - return matches[0] - - def findall(self, **kwargs): - """Find all items with attributes matching ``**kwargs``. - - This isn't very efficient: it loads the entire list then filters on - the Python side. - """ - found = [] - searches = kwargs.items() - - for obj in self.list(): - try: - if all(getattr(obj, attr) == value - for (attr, value) in searches): - found.append(obj) - except AttributeError: - continue - - return found - - -class CrudManager(BaseManager): - """Base manager class for manipulating entities. - - Children of this class are expected to define a `collection_key` and `key`. - - - `collection_key`: Usually a plural noun by convention (e.g. `entities`); - used to refer collections in both URL's (e.g. `/v3/entities`) and JSON - objects containing a list of member resources (e.g. `{'entities': [{}, - {}, {}]}`). - - `key`: Usually a singular noun by convention (e.g. `entity`); used to - refer to an individual member of the collection. - - """ - collection_key = None - key = None - - def build_url(self, base_url=None, **kwargs): - """Builds a resource URL for the given kwargs. - - Given an example collection where `collection_key = 'entities'` and - `key = 'entity'`, the following URL's could be generated. - - By default, the URL will represent a collection of entities, e.g.:: - - /entities - - If kwargs contains an `entity_id`, then the URL will represent a - specific member, e.g.:: - - /entities/{entity_id} - - :param base_url: if provided, the generated URL will be appended to it - """ - url = base_url if base_url is not None else '' - - url += '/%s' % self.collection_key - - # do we have a specific entity? - entity_id = kwargs.get('%s_id' % self.key) - if entity_id is not None: - url += '/%s' % entity_id - - return url - - def _filter_kwargs(self, kwargs): - """Drop null values and handle ids.""" - for key, ref in kwargs.copy().items(): - if ref is None: - kwargs.pop(key) - else: - if isinstance(ref, Resource): - kwargs.pop(key) - kwargs['%s_id' % key] = getid(ref) - return kwargs - - def create(self, **kwargs): - kwargs = self._filter_kwargs(kwargs) - return self._post( - self.build_url(**kwargs), - {self.key: kwargs}, - self.key) - - def get(self, **kwargs): - kwargs = self._filter_kwargs(kwargs) - return self._get( - self.build_url(**kwargs), - self.key) - - def head(self, **kwargs): - kwargs = self._filter_kwargs(kwargs) - return self._head(self.build_url(**kwargs)) - - def list(self, base_url=None, **kwargs): - """List the collection. - - :param base_url: if provided, the generated URL will be appended to it - """ - kwargs = self._filter_kwargs(kwargs) - - return self._list( - '%(base_url)s%(query)s' % { - 'base_url': self.build_url(base_url=base_url, **kwargs), - 'query': '?%s' % parse.urlencode(kwargs) if kwargs else '', - }, - self.collection_key) - - def put(self, base_url=None, **kwargs): - """Update an element. - - :param base_url: if provided, the generated URL will be appended to it - """ - kwargs = self._filter_kwargs(kwargs) - - return self._put(self.build_url(base_url=base_url, **kwargs)) - - def update(self, **kwargs): - kwargs = self._filter_kwargs(kwargs) - params = kwargs.copy() - params.pop('%s_id' % self.key) - - return self._patch( - self.build_url(**kwargs), - {self.key: params}, - self.key) - - def delete(self, **kwargs): - kwargs = self._filter_kwargs(kwargs) - - return self._delete( - self.build_url(**kwargs)) - - def find(self, base_url=None, **kwargs): - """Find a single item with attributes matching ``**kwargs``. - - :param base_url: if provided, the generated URL will be appended to it - """ - kwargs = self._filter_kwargs(kwargs) - - rl = self._list( - '%(base_url)s%(query)s' % { - 'base_url': self.build_url(base_url=base_url, **kwargs), - 'query': '?%s' % parse.urlencode(kwargs) if kwargs else '', - }, - self.collection_key) - num = len(rl) - - if num == 0: - msg = _("No %(name)s matching %(args)s.") % { - 'name': self.resource_class.__name__, - 'args': kwargs - } - raise exceptions.NotFound(msg) - elif num > 1: - raise exceptions.NoUniqueMatch - else: - return rl[0] - - -class Extension(HookableMixin): - """Extension descriptor.""" - - SUPPORTED_HOOKS = ('__pre_parse_args__', '__post_parse_args__') - manager_class = None - - def __init__(self, name, module): - super(Extension, self).__init__() - self.name = name - self.module = module - self._parse_extension_module() - - def _parse_extension_module(self): - self.manager_class = None - for attr_name, attr_value in self.module.__dict__.items(): - if attr_name in self.SUPPORTED_HOOKS: - self.add_hook(attr_name, attr_value) - else: - try: - if issubclass(attr_value, BaseManager): - self.manager_class = attr_value - except TypeError: - pass - - def __repr__(self): - return "" % self.name - - -class Resource(object): - """Base class for OpenStack resources (tenant, user, etc.). - - This is pretty much just a bag for attributes. - """ - - HUMAN_ID = False - NAME_ATTR = 'name' - - def __init__(self, manager, info, loaded=False): - """Populate and bind to a manager. - - :param manager: BaseManager object - :param info: dictionary representing resource attributes - :param loaded: prevent lazy-loading if set to True - """ - self.manager = manager - self._info = info - self._add_details(info) - self._loaded = loaded - - def __repr__(self): - reprkeys = sorted(k - for k in self.__dict__.keys() - if k[0] != '_' and k != 'manager') - info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) - return "<%s %s>" % (self.__class__.__name__, info) - - @property - def human_id(self): - """Human-readable ID which can be used for bash completion.""" - if self.HUMAN_ID: - name = getattr(self, self.NAME_ATTR, None) - if name is not None: - return strutils.to_slug(name) - return None - - def _add_details(self, info): - for (k, v) in info.items(): - try: - setattr(self, k, v) - self._info[k] = v - except AttributeError: - # In this case we already defined the attribute on the class - pass - - def __getattr__(self, k): - if k not in self.__dict__: - # NOTE(bcwaldon): disallow lazy-loading if already loaded once - if not self.is_loaded(): - self.get() - return self.__getattr__(k) - - raise AttributeError(k) - else: - return self.__dict__[k] - - def get(self): - """Support for lazy loading details. - - Some clients, such as novaclient have the option to lazy load the - details, details which can be loaded with this function. - """ - # set_loaded() first ... so if we have to bail, we know we tried. - self.set_loaded(True) - if not hasattr(self.manager, 'get'): - return - - new = self.manager.get(self.id) - if new: - self._add_details(new._info) - self._add_details( - {'x_request_id': self.manager.client.last_request_id}) - - def __eq__(self, other): - if not isinstance(other, Resource): - return NotImplemented - # two resources of different types are not equal - if not isinstance(other, self.__class__): - return False - return self._info == other._info - - def is_loaded(self): - return self._loaded - - def set_loaded(self, val): - self._loaded = val - - def to_dict(self): - return copy.deepcopy(self._info) diff --git a/ironicclient/common/apiclient/exceptions.py b/ironicclient/common/apiclient/exceptions.py deleted file mode 100644 index 81a3340..0000000 --- a/ironicclient/common/apiclient/exceptions.py +++ /dev/null @@ -1,469 +0,0 @@ -# Copyright 2010 Jacob Kaplan-Moss -# Copyright 2011 Nebula, Inc. -# Copyright 2013 Alessio Ababilov -# Copyright 2013 OpenStack Foundation -# 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. - -""" -Exception definitions. -""" - - -import inspect -import sys - -import six -from six.moves import http_client - -from ironicclient.common.i18n import _ - - -class ClientException(Exception): - """The base exception class for all exceptions this library raises.""" - pass - - -class ValidationError(ClientException): - """Error in validation on API client side.""" - pass - - -class UnsupportedVersion(ClientException): - """User is trying to use an unsupported version of the API.""" - pass - - -class CommandError(ClientException): - """Error in CLI tool.""" - pass - - -class AuthorizationFailure(ClientException): - """Cannot authorize API client.""" - pass - - -class ConnectionError(ClientException): - """Cannot connect to API service.""" - pass - - -class ConnectionRefused(ConnectionError): - """Connection refused while trying to connect to API service.""" - pass - - -class AuthPluginOptionsMissing(AuthorizationFailure): - """Auth plugin misses some options.""" - def __init__(self, opt_names): - super(AuthPluginOptionsMissing, self).__init__( - _("Authentication failed. Missing options: %s") % - ", ".join(opt_names)) - self.opt_names = opt_names - - -class AuthSystemNotFound(AuthorizationFailure): - """User has specified an AuthSystem that is not installed.""" - def __init__(self, auth_system): - super(AuthSystemNotFound, self).__init__( - _("AuthSystemNotFound: %r") % auth_system) - self.auth_system = auth_system - - -class NoUniqueMatch(ClientException): - """Multiple entities found instead of one.""" - pass - - -class EndpointException(ClientException): - """Something is rotten in Service Catalog.""" - pass - - -class EndpointNotFound(EndpointException): - """Could not find requested endpoint in Service Catalog.""" - pass - - -class AmbiguousEndpoints(EndpointException): - """Found more than one matching endpoint in Service Catalog.""" - def __init__(self, endpoints=None): - super(AmbiguousEndpoints, self).__init__( - _("AmbiguousEndpoints: %r") % endpoints) - self.endpoints = endpoints - - -class HttpError(ClientException): - """The base exception class for all HTTP exceptions.""" - http_status = 0 - message = _("HTTP Error") - - def __init__(self, message=None, details=None, - response=None, request_id=None, - url=None, method=None, http_status=None): - self.http_status = http_status or self.http_status - self.message = message or self.message - self.details = details - self.request_id = request_id - self.response = response - self.url = url - self.method = method - formatted_string = "%s (HTTP %s)" % (self.message, self.http_status) - if request_id: - formatted_string += " (Request-ID: %s)" % request_id - super(HttpError, self).__init__(formatted_string) - - -class HTTPRedirection(HttpError): - """HTTP Redirection.""" - message = _("HTTP Redirection") - - -class HTTPClientError(HttpError): - """Client-side HTTP error. - - Exception for cases in which the client seems to have erred. - """ - message = _("HTTP Client Error") - - -class HttpServerError(HttpError): - """Server-side HTTP error. - - Exception for cases in which the server is aware that it has - erred or is incapable of performing the request. - """ - message = _("HTTP Server Error") - - -class MultipleChoices(HTTPRedirection): - """HTTP 300 - Multiple Choices. - - Indicates multiple options for the resource that the client may follow. - """ - - http_status = http_client.MULTIPLE_CHOICES - message = _("Multiple Choices") - - -class BadRequest(HTTPClientError): - """HTTP 400 - Bad Request. - - The request cannot be fulfilled due to bad syntax. - """ - http_status = http_client.BAD_REQUEST - message = _("Bad Request") - - -class Unauthorized(HTTPClientError): - """HTTP 401 - Unauthorized. - - Similar to 403 Forbidden, but specifically for use when authentication - is required and has failed or has not yet been provided. - """ - http_status = http_client.UNAUTHORIZED - message = _("Unauthorized") - - -class PaymentRequired(HTTPClientError): - """HTTP 402 - Payment Required. - - Reserved for future use. - """ - http_status = http_client.PAYMENT_REQUIRED - message = _("Payment Required") - - -class Forbidden(HTTPClientError): - """HTTP 403 - Forbidden. - - The request was a valid request, but the server is refusing to respond - to it. - """ - http_status = http_client.FORBIDDEN - message = _("Forbidden") - - -class NotFound(HTTPClientError): - """HTTP 404 - Not Found. - - The requested resource could not be found but may be available again - in the future. - """ - http_status = http_client.NOT_FOUND - message = _("Not Found") - - -class MethodNotAllowed(HTTPClientError): - """HTTP 405 - Method Not Allowed. - - A request was made of a resource using a request method not supported - by that resource. - """ - http_status = http_client.METHOD_NOT_ALLOWED - message = _("Method Not Allowed") - - -class NotAcceptable(HTTPClientError): - """HTTP 406 - Not Acceptable. - - The requested resource is only capable of generating content not - acceptable according to the Accept headers sent in the request. - """ - http_status = http_client.NOT_ACCEPTABLE - message = _("Not Acceptable") - - -class ProxyAuthenticationRequired(HTTPClientError): - """HTTP 407 - Proxy Authentication Required. - - The client must first authenticate itself with the proxy. - """ - http_status = http_client.PROXY_AUTHENTICATION_REQUIRED - message = _("Proxy Authentication Required") - - -class RequestTimeout(HTTPClientError): - """HTTP 408 - Request Timeout. - - The server timed out waiting for the request. - """ - http_status = http_client.REQUEST_TIMEOUT - message = _("Request Timeout") - - -class Conflict(HTTPClientError): - """HTTP 409 - Conflict. - - Indicates that the request could not be processed because of conflict - in the request, such as an edit conflict. - """ - http_status = http_client.CONFLICT - message = _("Conflict") - - -class Gone(HTTPClientError): - """HTTP 410 - Gone. - - Indicates that the resource requested is no longer available and will - not be available again. - """ - http_status = http_client.GONE - message = _("Gone") - - -class LengthRequired(HTTPClientError): - """HTTP 411 - Length Required. - - The request did not specify the length of its content, which is - required by the requested resource. - """ - http_status = http_client.LENGTH_REQUIRED - message = _("Length Required") - - -class PreconditionFailed(HTTPClientError): - """HTTP 412 - Precondition Failed. - - The server does not meet one of the preconditions that the requester - put on the request. - """ - http_status = http_client.PRECONDITION_FAILED - message = _("Precondition Failed") - - -class RequestEntityTooLarge(HTTPClientError): - """HTTP 413 - Request Entity Too Large. - - The request is larger than the server is willing or able to process. - """ - http_status = http_client.REQUEST_ENTITY_TOO_LARGE - message = _("Request Entity Too Large") - - def __init__(self, *args, **kwargs): - try: - self.retry_after = int(kwargs.pop('retry_after')) - except (KeyError, ValueError): - self.retry_after = 0 - - super(RequestEntityTooLarge, self).__init__(*args, **kwargs) - - -class RequestUriTooLong(HTTPClientError): - """HTTP 414 - Request-URI Too Long. - - The URI provided was too long for the server to process. - """ - http_status = http_client.REQUEST_URI_TOO_LONG - message = _("Request-URI Too Long") - - -class UnsupportedMediaType(HTTPClientError): - """HTTP 415 - Unsupported Media Type. - - The request entity has a media type which the server or resource does - not support. - """ - http_status = http_client.UNSUPPORTED_MEDIA_TYPE - message = _("Unsupported Media Type") - - -class RequestedRangeNotSatisfiable(HTTPClientError): - """HTTP 416 - Requested Range Not Satisfiable. - - The client has asked for a portion of the file, but the server cannot - supply that portion. - """ - http_status = http_client.REQUESTED_RANGE_NOT_SATISFIABLE - message = _("Requested Range Not Satisfiable") - - -class ExpectationFailed(HTTPClientError): - """HTTP 417 - Expectation Failed. - - The server cannot meet the requirements of the Expect request-header field. - """ - http_status = http_client.EXPECTATION_FAILED - message = _("Expectation Failed") - - -class UnprocessableEntity(HTTPClientError): - """HTTP 422 - Unprocessable Entity. - - The request was well-formed but was unable to be followed due to semantic - errors. - """ - http_status = http_client.UNPROCESSABLE_ENTITY - message = _("Unprocessable Entity") - - -class InternalServerError(HttpServerError): - """HTTP 500 - Internal Server Error. - - A generic error message, given when no more specific message is suitable. - """ - http_status = http_client.INTERNAL_SERVER_ERROR - message = _("Internal Server Error") - - -# NotImplemented is a python keyword. -class HttpNotImplemented(HttpServerError): - """HTTP 501 - Not Implemented. - - The server either does not recognize the request method, or it lacks - the ability to fulfill the request. - """ - http_status = http_client.NOT_IMPLEMENTED - message = _("Not Implemented") - - -class BadGateway(HttpServerError): - """HTTP 502 - Bad Gateway. - - The server was acting as a gateway or proxy and received an invalid - response from the upstream server. - """ - http_status = http_client.BAD_GATEWAY - message = _("Bad Gateway") - - -class ServiceUnavailable(HttpServerError): - """HTTP 503 - Service Unavailable. - - The server is currently unavailable. - """ - http_status = http_client.SERVICE_UNAVAILABLE - message = _("Service Unavailable") - - -class GatewayTimeout(HttpServerError): - """HTTP 504 - Gateway Timeout. - - The server was acting as a gateway or proxy and did not receive a timely - response from the upstream server. - """ - http_status = http_client.GATEWAY_TIMEOUT - message = _("Gateway Timeout") - - -class HttpVersionNotSupported(HttpServerError): - """HTTP 505 - HttpVersion Not Supported. - - The server does not support the HTTP protocol version used in the request. - """ - http_status = http_client.HTTP_VERSION_NOT_SUPPORTED - message = _("HTTP Version Not Supported") - - -# _code_map contains all the classes that have http_status attribute. -_code_map = dict( - (getattr(obj, 'http_status', None), obj) - for name, obj in vars(sys.modules[__name__]).items() - if inspect.isclass(obj) and getattr(obj, 'http_status', False) -) - - -def from_response(response, method, url): - """Returns an instance of :class:`HttpError` or subclass based on response. - - :param response: instance of `requests.Response` class - :param method: HTTP method used for request - :param url: URL used for request - """ - - req_id = response.headers.get("x-openstack-request-id") - # NOTE(hdd) true for older versions of nova and cinder - if not req_id: - req_id = response.headers.get("x-compute-request-id") - kwargs = { - "http_status": response.status_code, - "response": response, - "method": method, - "url": url, - "request_id": req_id, - } - if "retry-after" in response.headers: - kwargs["retry_after"] = response.headers["retry-after"] - - content_type = response.headers.get("Content-Type", "") - if content_type.startswith("application/json"): - try: - body = response.json() - except ValueError: - pass - else: - if isinstance(body, dict): - error = body.get(list(body)[0]) - if isinstance(error, dict): - kwargs["message"] = (error.get("message") or - error.get("faultstring")) - kwargs["details"] = (error.get("details") or - six.text_type(body)) - elif content_type.startswith("text/"): - kwargs["details"] = getattr(response, 'text', '') - - try: - cls = _code_map[response.status_code] - except KeyError: - # 5XX status codes are server errors - if response.status_code >= http_client.INTERNAL_SERVER_ERROR: - cls = HttpServerError - # 4XX status codes are client request errors - elif (http_client.BAD_REQUEST <= response.status_code < - http_client.INTERNAL_SERVER_ERROR): - cls = HTTPClientError - else: - cls = HttpError - return cls(**kwargs) diff --git a/ironicclient/common/base.py b/ironicclient/common/base.py deleted file mode 100644 index 294f06a..0000000 --- a/ironicclient/common/base.py +++ /dev/null @@ -1,249 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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. - -""" -Base utilities to build API operation managers and objects on top of. -""" - -import abc -import copy -import six - -import six.moves.urllib.parse as urlparse - -from ironicclient.common.apiclient import base -from ironicclient import exc - - -def getid(obj): - """Wrapper to get object's ID. - - Abstracts the common pattern of allowing both an object or an - object's ID (UUID) as a parameter when dealing with relationships. - """ - try: - return obj.id - except AttributeError: - return obj - - -@six.add_metaclass(abc.ABCMeta) -class Manager(object): - """Provides CRUD operations with a particular API.""" - - def __init__(self, api): - self.api = api - - def _path(self, resource_id=None): - """Returns a request path for a given resource identifier. - - :param resource_id: Identifier of the resource to generate the request - path. - """ - return ('/v1/%s/%s' % (self._resource_name, resource_id) - if resource_id else '/v1/%s' % self._resource_name) - - @abc.abstractproperty - def resource_class(self): - """The resource class - - """ - - @abc.abstractproperty - def _resource_name(self): - """The resource name. - - """ - - def _get(self, resource_id, fields=None): - """Retrieve a resource. - - :param resource_id: Identifier of the resource. - :param fields: List of specific fields to be returned. - :raises exc.ValidationError: For invalid resource_id arg value. - """ - - if not resource_id: - raise exc.ValidationError( - "The identifier argument is invalid. " - "Value provided: {!r}".format(resource_id)) - - if fields is not None: - resource_id = '%s?fields=' % resource_id - resource_id += ','.join(fields) - - try: - return self._list(self._path(resource_id))[0] - except IndexError: - return None - - def _get_as_dict(self, resource_id, fields=None): - """Retrieve a resource as a dictionary - - :param resource_id: Identifier of the resource. - :param fields: List of specific fields to be returned. - :returns: a dictionary representing the resource; may be empty - """ - - resource = self._get(resource_id, fields=fields) - if resource: - return resource.to_dict() - else: - return {} - - def _format_body_data(self, body, response_key): - if response_key: - try: - data = body[response_key] - except KeyError: - return [] - else: - data = body - - if not isinstance(data, list): - data = [data] - - return data - - def _list_pagination(self, url, response_key=None, obj_class=None, - limit=None): - """Retrieve a list of items. - - The Ironic API is configured to return a maximum number of - items per request, (see Ironic's api.max_limit option). This - iterates over the 'next' link (pagination) in the responses, - to get the number of items specified by 'limit'. If 'limit' - is None this function will continue pagination until there are - no more values to be returned. - - :param url: a partial URL, e.g. '/nodes' - :param response_key: the key to be looked up in response - dictionary, e.g. 'nodes' - :param obj_class: class for constructing the returned objects. - :param limit: maximum number of items to return. If None returns - everything. - - """ - if obj_class is None: - obj_class = self.resource_class - - if limit is not None: - limit = int(limit) - - object_list = [] - object_count = 0 - limit_reached = False - while url: - resp, body = self.api.json_request('GET', url) - data = self._format_body_data(body, response_key) - for obj in data: - object_list.append(obj_class(self, obj, loaded=True)) - object_count += 1 - if limit and object_count >= limit: - # break the for loop - limit_reached = True - break - - # break the while loop and return - if limit_reached: - break - - url = body.get('next') - if url: - # NOTE(lucasagomes): We need to edit the URL to remove - # the scheme and netloc - url_parts = list(urlparse.urlparse(url)) - url_parts[0] = url_parts[1] = '' - url = urlparse.urlunparse(url_parts) - - return object_list - - def _list(self, url, response_key=None, obj_class=None, body=None): - resp, body = self.api.json_request('GET', url) - - if obj_class is None: - obj_class = self.resource_class - - data = self._format_body_data(body, response_key) - return [obj_class(self, res, loaded=True) for res in data if res] - - def _update(self, resource_id, patch, method='PATCH'): - """Update a resource. - - :param resource_id: Resource identifier. - :param patch: New version of a given resource. - :param method: Name of the method for the request. - """ - - url = self._path(resource_id) - resp, body = self.api.json_request(method, url, body=patch) - # PATCH/PUT requests may not return a body - if body: - return self.resource_class(self, body) - - def _delete(self, resource_id): - """Delete a resource. - - :param resource_id: Resource identifier. - """ - self.api.raw_request('DELETE', self._path(resource_id)) - - -@six.add_metaclass(abc.ABCMeta) -class CreateManager(Manager): - """Provides creation operations with a particular API.""" - - @abc.abstractproperty - def _creation_attributes(self): - """A list of required creation attributes for a resource type. - - """ - - def create(self, **kwargs): - """Create a resource based on a kwargs dictionary of attributes. - - :param kwargs: A dictionary containing the attributes of the resource - that will be created. - :raises exc.InvalidAttribute: For invalid attributes that are not - needed to create the resource. - """ - - new = {} - invalid = [] - for (key, value) in kwargs.items(): - if key in self._creation_attributes: - new[key] = value - else: - invalid.append(key) - if invalid: - raise exc.InvalidAttribute( - 'The attribute(s) "%(attrs)s" are invalid; they are not ' - 'needed to create %(resource)s.' % - {'resource': self._resource_name, - 'attrs': '","'.join(invalid)}) - url = self._path() - resp, body = self.api.json_request('POST', url, body=new) - if body: - return self.resource_class(self, body) - - -class Resource(base.Resource): - """Represents a particular instance of an object (tenant, user, etc). - - This is pretty much just a bag for attributes. - """ - - def to_dict(self): - return copy.deepcopy(self._info) diff --git a/ironicclient/common/cliutils.py b/ironicclient/common/cliutils.py deleted file mode 100644 index c5fb9cf..0000000 --- a/ironicclient/common/cliutils.py +++ /dev/null @@ -1,296 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# -# 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. - -# W0603: Using the global statement -# W0621: Redefining name %s from outer scope -# pylint: disable=W0603,W0621 - -from __future__ import print_function - -import getpass -import inspect -import json -import os -import sys -import textwrap - -from oslo_utils import encodeutils -from oslo_utils import strutils -import prettytable -import six -from six import moves - -from ironicclient.common.i18n import _ - - -class MissingArgs(Exception): - """Supplied arguments are not sufficient for calling a function.""" - def __init__(self, missing): - self.missing = missing - msg = _("Missing arguments: %s") % ", ".join(missing) - super(MissingArgs, self).__init__(msg) - - -def validate_args(fn, *args, **kwargs): - """Check that the supplied args are sufficient for calling a function. - - >>> validate_args(lambda a: None) - Traceback (most recent call last): - ... - MissingArgs: Missing argument(s): a - >>> validate_args(lambda a, b, c, d: None, 0, c=1) - Traceback (most recent call last): - ... - MissingArgs: Missing argument(s): b, d - - :param fn: the function to check - :param args: the positional arguments supplied - :param kwargs: the keyword arguments supplied - """ - argspec = inspect.getargspec(fn) - - num_defaults = len(argspec.defaults or []) - required_args = argspec.args[:len(argspec.args) - num_defaults] - - def isbound(method): - return getattr(method, '__self__', None) is not None - - if isbound(fn): - required_args.pop(0) - - missing = [arg for arg in required_args if arg not in kwargs] - missing = missing[len(args):] - if missing: - raise MissingArgs(missing) - - -def arg(*args, **kwargs): - """Decorator for CLI args. - - Example: - - >>> @arg("name", help="Name of the new entity") - ... def entity_create(args): - ... pass - """ - def _decorator(func): - add_arg(func, *args, **kwargs) - return func - return _decorator - - -def env(*args, **kwargs): - """Returns the first environment variable set. - - If all are empty, defaults to '' or keyword arg `default`. - """ - for arg in args: - value = os.environ.get(arg) - if value: - return value - return kwargs.get('default', '') - - -def add_arg(func, *args, **kwargs): - """Bind CLI arguments to a shell.py `do_foo` function.""" - - if not hasattr(func, 'arguments'): - func.arguments = [] - - # NOTE(sirp): avoid dups that can occur when the module is shared across - # tests. - if (args, kwargs) not in func.arguments: - # Because of the semantics of decorator composition if we just append - # to the options list positional options will appear to be backwards. - func.arguments.insert(0, (args, kwargs)) - - -def unauthenticated(func): - """Adds 'unauthenticated' attribute to decorated function. - - Usage: - - >>> @unauthenticated - ... def mymethod(f): - ... pass - """ - func.unauthenticated = True - return func - - -def isunauthenticated(func): - """Checks if the function does not require authentication. - - Mark such functions with the `@unauthenticated` decorator. - - :returns: bool - """ - return getattr(func, 'unauthenticated', False) - - -def print_list(objs, fields, formatters=None, sortby_index=0, - mixed_case_fields=None, field_labels=None, json_flag=False): - """Print a list of objects or dict as a table, one row per object or dict. - - :param objs: iterable of :class:`Resource` - :param fields: attributes that correspond to columns, in order - :param formatters: `dict` of callables for field formatting - :param sortby_index: index of the field for sorting table rows - :param mixed_case_fields: fields corresponding to object attributes that - have mixed case names (e.g., 'serverId') - :param field_labels: Labels to use in the heading of the table, default to - fields. - :param json_flag: print the list as JSON instead of table - """ - def _get_name_and_data(field): - if field in formatters: - # The value of the field has to be modified. - # For example, it can be used to add extra fields. - return (field, formatters[field](o)) - - field_name = field.replace(' ', '_') - if field not in mixed_case_fields: - field_name = field.lower() - if isinstance(o, dict): - data = o.get(field_name, '') - else: - data = getattr(o, field_name, '') - return (field_name, data) - - formatters = formatters or {} - mixed_case_fields = mixed_case_fields or [] - field_labels = field_labels or fields - if len(field_labels) != len(fields): - raise ValueError(_("Field labels list %(labels)s has different number " - "of elements than fields list %(fields)s"), - {'labels': field_labels, 'fields': fields}) - - if sortby_index is None: - kwargs = {} - else: - kwargs = {'sortby': field_labels[sortby_index]} - pt = prettytable.PrettyTable(field_labels) - pt.align = 'l' - - json_array = [] - - for o in objs: - row = [] - for field in fields: - row.append(_get_name_and_data(field)) - if json_flag: - json_array.append(dict(row)) - else: - pt.add_row([r[1] for r in row]) - - if json_flag: - print(json.dumps(json_array, indent=4, separators=(',', ': '))) - elif six.PY3: - print(encodeutils.safe_encode(pt.get_string(**kwargs)).decode()) - else: - print(encodeutils.safe_encode(pt.get_string(**kwargs))) - - -def print_dict(dct, dict_property="Property", wrap=0, dict_value='Value', - json_flag=False): - """Print a `dict` as a table of two columns. - - :param dct: `dict` to print - :param dict_property: name of the first column - :param wrap: wrapping for the second column - :param dict_value: header label for the value (second) column - :param json_flag: print `dict` as JSON instead of table - """ - if json_flag: - print(json.dumps(dct, indent=4, separators=(',', ': '))) - return - pt = prettytable.PrettyTable([dict_property, dict_value]) - pt.align = 'l' - for k, v in sorted(dct.items()): - # convert dict to str to check length - if isinstance(v, dict): - v = six.text_type(v) - if wrap > 0: - v = textwrap.fill(six.text_type(v), wrap) - elif wrap < 0: - raise ValueError(_("wrap argument should be a non-negative " - "integer")) - # if value has a newline, add in multiple rows - # e.g. fault with stacktrace - if v and isinstance(v, six.string_types) and r'\n' in v: - lines = v.strip().split(r'\n') - col1 = k - for line in lines: - pt.add_row([col1, line]) - col1 = '' - else: - pt.add_row([k, v]) - - if six.PY3: - print(encodeutils.safe_encode(pt.get_string()).decode()) - else: - print(encodeutils.safe_encode(pt.get_string())) - - -def get_password(max_password_prompts=3): - """Read password from TTY.""" - verify = strutils.bool_from_string(env("OS_VERIFY_PASSWORD")) - pw = None - if hasattr(sys.stdin, "isatty") and sys.stdin.isatty(): - # Check for Ctrl-D - try: - for __ in moves.range(max_password_prompts): - pw1 = getpass.getpass("OS Password: ") - if verify: - pw2 = getpass.getpass("Please verify: ") - else: - pw2 = pw1 - if pw1 == pw2 and pw1: - pw = pw1 - break - except EOFError: - pass - return pw - - -def service_type(stype): - """Adds 'service_type' attribute to decorated function. - - Usage: - - .. code-block:: python - - @service_type('volume') - def mymethod(f): - ... - """ - def inner(f): - f.service_type = stype - return f - return inner - - -def get_service_type(f): - """Retrieves service type from function.""" - return getattr(f, 'service_type', None) - - -def pretty_choice_list(l): - return ', '.join("'%s'" % i for i in l) - - -def exit(msg=''): - if msg: - print(msg, file=sys.stderr) - sys.exit(1) diff --git a/ironicclient/common/filecache.py b/ironicclient/common/filecache.py deleted file mode 100644 index d4fdf34..0000000 --- a/ironicclient/common/filecache.py +++ /dev/null @@ -1,103 +0,0 @@ -# -# Copyright 2015 Rackspace, 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 logging -import os - -import appdirs -import dogpile.cache - - -LOG = logging.getLogger(__name__) - -AUTHOR = 'openstack' -PROGNAME = 'python-ironicclient' - -CACHE = None -CACHE_DIR = appdirs.user_cache_dir(PROGNAME, AUTHOR) -CACHE_EXPIRY_ENV_VAR = 'IRONICCLIENT_CACHE_EXPIRY' # environment variable -CACHE_FILENAME = os.path.join(CACHE_DIR, 'ironic-api-version.dbm') -DEFAULT_EXPIRY = 300 # seconds - - -def _get_cache(): - """Configure file caching.""" - global CACHE - if CACHE is None: - - # Ensure cache directory present - if not os.path.exists(CACHE_DIR): - os.makedirs(CACHE_DIR) - - # Use the cache expiry if specified in an env var - expiry_time = os.environ.get(CACHE_EXPIRY_ENV_VAR, DEFAULT_EXPIRY) - try: - expiry_time = int(expiry_time) - except ValueError: - LOG.warning("Environment variable %(env_var)s should be an " - "integer (not '%(curr_val)s'). Using default " - "expiry of %(default)s seconds instead.", - {'env_var': CACHE_EXPIRY_ENV_VAR, - 'curr_val': expiry_time, - 'default': DEFAULT_EXPIRY}) - expiry_time = DEFAULT_EXPIRY - - CACHE = dogpile.cache.make_region(key_mangler=str).configure( - 'dogpile.cache.dbm', - expiration_time=expiry_time, - arguments={ - "filename": CACHE_FILENAME, - } - ) - return CACHE - - -def _build_key(host, port): - """Build a key based upon the hostname or address supplied.""" - return "%s:%s" % (host, port) - - -def save_data(host, port, data): - """Save 'data' for a particular 'host' in the appropriate cache dir. - - param host: The host that we need to save data for - param port: The port on the host that we need to save data for - param data: The data we want saved - """ - key = _build_key(host, port) - _get_cache().set(key, data) - - -def retrieve_data(host, port, expiry=None): - """Retrieve the version stored for an ironic 'host', if it's not stale. - - Check to see if there is valid cached data for the host/port - combination and return that if it isn't stale. - - param host: The host that we need to retrieve data for - param port: The port on the host that we need to retrieve data for - param expiry: The age in seconds before cached data is deemed invalid - """ - # Ensure that a cache file exists first - if not os.path.isfile(CACHE_FILENAME): - return None - - key = _build_key(host, port) - data = _get_cache().get(key, expiration_time=expiry) - - if data == dogpile.cache.api.NO_VALUE: - return None - return data diff --git a/ironicclient/common/http.py b/ironicclient/common/http.py deleted file mode 100644 index d4b60bb..0000000 --- a/ironicclient/common/http.py +++ /dev/null @@ -1,640 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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 copy -from distutils.version import StrictVersion -import functools -import hashlib -import logging -import os -import socket -import ssl -import textwrap -import time - -from keystoneauth1 import adapter -from keystoneauth1 import exceptions as kexc -from oslo_serialization import jsonutils -from oslo_utils import strutils -import requests -import six -from six.moves import http_client -import six.moves.urllib.parse as urlparse - -from ironicclient.common import filecache -from ironicclient.common.i18n import _ -from ironicclient import exc - - -# NOTE(deva): Record the latest version that this client was tested with. -# We still have a lot of work to do in the client to implement -# microversion support in the client properly! See -# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa -# for full details. -DEFAULT_VER = '1.9' - - -LOG = logging.getLogger(__name__) -USER_AGENT = 'python-ironicclient' -CHUNKSIZE = 1024 * 64 # 64kB - -API_VERSION = '/v1' -API_VERSION_SELECTED_STATES = ('user', 'negotiated', 'cached', 'default') - - -DEFAULT_MAX_RETRIES = 5 -DEFAULT_RETRY_INTERVAL = 2 -SENSITIVE_HEADERS = ('X-Auth-Token',) - - -SUPPORTED_ENDPOINT_SCHEME = ('http', 'https') - - -def _trim_endpoint_api_version(url): - """Trim API version and trailing slash from endpoint.""" - return url.rstrip('/').rstrip(API_VERSION) - - -def _extract_error_json(body): - """Return error_message from the HTTP response body.""" - error_json = {} - try: - body_json = jsonutils.loads(body) - if 'error_message' in body_json: - raw_msg = body_json['error_message'] - error_json = jsonutils.loads(raw_msg) - except ValueError: - pass - - return error_json - - -def get_server(endpoint): - """Extract and return the server & port that we're connecting to.""" - if endpoint is None: - return None, None - parts = urlparse.urlparse(endpoint) - return parts.hostname, str(parts.port) - - -class VersionNegotiationMixin(object): - def negotiate_version(self, conn, resp): - """Negotiate the server version - - Assumption: Called after receiving a 406 error when doing a request. - - param conn: A connection object - param resp: The response object from http request - """ - if self.api_version_select_state not in API_VERSION_SELECTED_STATES: - raise RuntimeError( - _('Error: self.api_version_select_state should be one of the ' - 'values in: "%(valid)s" but had the value: "%(value)s"') % - {'valid': ', '.join(API_VERSION_SELECTED_STATES), - 'value': self.api_version_select_state}) - min_ver, max_ver = self._parse_version_headers(resp) - # NOTE: servers before commit 32fb6e99 did not return version headers - # on error, so we need to perform a GET to determine - # the supported version range - if not max_ver: - LOG.debug('No version header in response, requesting from server') - if self.os_ironic_api_version: - base_version = ("/v%s" % - str(self.os_ironic_api_version).split('.')[0]) - else: - base_version = API_VERSION - resp = self._make_simple_request(conn, 'GET', base_version) - min_ver, max_ver = self._parse_version_headers(resp) - # If the user requested an explicit version or we have negotiated a - # version and still failing then error now. The server could - # support the version requested but the requested operation may not - # be supported by the requested version. - if self.api_version_select_state == 'user': - raise exc.UnsupportedVersion(textwrap.fill( - _("Requested API version %(req)s is not supported by the " - "server or the requested operation is not supported by the " - "requested version. Supported version range is %(min)s to " - "%(max)s") - % {'req': self.os_ironic_api_version, - 'min': min_ver, 'max': max_ver})) - if self.api_version_select_state == 'negotiated': - raise exc.UnsupportedVersion(textwrap.fill( - _("No API version was specified and the requested operation " - "was not supported by the client's negotiated API version " - "%(req)s. Supported version range is: %(min)s to %(max)s") - % {'req': self.os_ironic_api_version, - 'min': min_ver, 'max': max_ver})) - - negotiated_ver = str(min(StrictVersion(self.os_ironic_api_version), - StrictVersion(max_ver))) - if negotiated_ver < min_ver: - negotiated_ver = min_ver - # server handles microversions, but doesn't support - # the requested version, so try a negotiated version - self.api_version_select_state = 'negotiated' - self.os_ironic_api_version = negotiated_ver - LOG.debug('Negotiated API version is %s', negotiated_ver) - - # Cache the negotiated version for this server - host, port = get_server(self.endpoint) - filecache.save_data(host=host, port=port, data=negotiated_ver) - - return negotiated_ver - - def _generic_parse_version_headers(self, accessor_func): - min_ver = accessor_func('X-OpenStack-Ironic-API-Minimum-Version', - None) - max_ver = accessor_func('X-OpenStack-Ironic-API-Maximum-Version', - None) - return min_ver, max_ver - - def _parse_version_headers(self, accessor_func): - # NOTE(jlvillal): Declared for unit testing purposes - raise NotImplementedError() - - def _make_simple_request(self, conn, method, url): - # NOTE(jlvillal): Declared for unit testing purposes - raise NotImplementedError() - - -_RETRY_EXCEPTIONS = (exc.Conflict, exc.ServiceUnavailable, - exc.ConnectionRefused, kexc.RetriableConnectionFailure) - - -def with_retries(func): - """Wrapper for _http_request adding support for retries.""" - @functools.wraps(func) - def wrapper(self, url, method, **kwargs): - if self.conflict_max_retries is None: - self.conflict_max_retries = DEFAULT_MAX_RETRIES - if self.conflict_retry_interval is None: - self.conflict_retry_interval = DEFAULT_RETRY_INTERVAL - - num_attempts = self.conflict_max_retries + 1 - for attempt in range(1, num_attempts + 1): - try: - return func(self, url, method, **kwargs) - except _RETRY_EXCEPTIONS as error: - msg = ("Error contacting Ironic server: %(error)s. " - "Attempt %(attempt)d of %(total)d" % - {'attempt': attempt, - 'total': num_attempts, - 'error': error}) - if attempt == num_attempts: - LOG.error(msg) - raise - else: - LOG.debug(msg) - time.sleep(self.conflict_retry_interval) - - return wrapper - - -class HTTPClient(VersionNegotiationMixin): - - def __init__(self, endpoint, **kwargs): - self.endpoint = endpoint - self.endpoint_trimmed = _trim_endpoint_api_version(endpoint) - self.auth_token = kwargs.get('token') - self.auth_ref = kwargs.get('auth_ref') - self.os_ironic_api_version = kwargs.get('os_ironic_api_version', - DEFAULT_VER) - self.api_version_select_state = kwargs.get( - 'api_version_select_state', 'default') - self.conflict_max_retries = kwargs.pop('max_retries', - DEFAULT_MAX_RETRIES) - self.conflict_retry_interval = kwargs.pop('retry_interval', - DEFAULT_RETRY_INTERVAL) - self.session = requests.Session() - - parts = urlparse.urlparse(endpoint) - if parts.scheme not in SUPPORTED_ENDPOINT_SCHEME: - msg = _('Unsupported scheme: %s') % parts.scheme - raise exc.EndpointException(msg) - - if parts.scheme == 'https': - if kwargs.get('insecure') is True: - self.session.verify = False - elif kwargs.get('ca_file'): - self.session.verify = kwargs['ca_file'] - self.session.cert = (kwargs.get('cert_file'), - kwargs.get('key_file')) - - def _process_header(self, name, value): - """Redacts any sensitive header - - Redact a header that contains sensitive information, by returning an - updated header with the sha1 hash of that value. The redacted value is - prefixed by '{SHA1}' because that's the convention used within - OpenStack. - - :returns: A tuple of (name, value) - name: the safe encoding format of name - value: the redacted value if name is x-auth-token, - or the safe encoding format of name - - """ - if name in SENSITIVE_HEADERS: - v = value.encode('utf-8') - h = hashlib.sha1(v) - d = h.hexdigest() - return (name, "{SHA1}%s" % d) - else: - return (name, value) - - def log_curl_request(self, method, url, kwargs): - curl = ['curl -i -X %s' % method] - - for (key, value) in kwargs['headers'].items(): - header = '-H \'%s: %s\'' % self._process_header(key, value) - curl.append(header) - - if not self.session.verify: - curl.append('-k') - elif isinstance(self.session.verify, six.string_types): - curl.append('--cacert %s' % self.session.verify) - - if self.session.cert: - curl.append('--cert %s' % self.session.cert[0]) - curl.append('--key %s' % self.session.cert[1]) - - if 'body' in kwargs: - body = strutils.mask_password(kwargs['body']) - curl.append('-d \'%s\'' % body) - - curl.append(urlparse.urljoin(self.endpoint_trimmed, url)) - LOG.debug(' '.join(curl)) - - @staticmethod - def log_http_response(resp, body=None): - # NOTE(aarefiev): resp.raw is urllib3 response object, it's used - # only to get 'version', response from request with 'stream = True' - # should be used for raw reading. - status = (resp.raw.version / 10.0, resp.status_code, resp.reason) - dump = ['\nHTTP/%.1f %s %s' % status] - dump.extend(['%s: %s' % (k, v) for k, v in resp.headers.items()]) - dump.append('') - if body: - body = strutils.mask_password(body) - dump.extend([body, '']) - LOG.debug('\n'.join(dump)) - - def _make_connection_url(self, url): - return urlparse.urljoin(self.endpoint_trimmed, url) - - def _parse_version_headers(self, resp): - return self._generic_parse_version_headers(resp.headers.get) - - def _make_simple_request(self, conn, method, url): - return conn.request(method, self._make_connection_url(url)) - - @with_retries - def _http_request(self, url, method, **kwargs): - """Send an http request with the specified characteristics. - - Wrapper around request.Session.request to handle tasks such - as setting headers and error handling. - """ - # Copy the kwargs so we can reuse the original in case of redirects - kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) - kwargs['headers'].setdefault('User-Agent', USER_AGENT) - if self.os_ironic_api_version: - kwargs['headers'].setdefault('X-OpenStack-Ironic-API-Version', - self.os_ironic_api_version) - if self.auth_token: - kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) - - self.log_curl_request(method, url, kwargs) - - # NOTE(aarefiev): This is for backwards compatibility, request - # expected body in 'data' field, previously we used httplib, - # which expected 'body' field. - body = kwargs.pop('body', None) - if body: - kwargs['data'] = body - - conn_url = self._make_connection_url(url) - try: - resp = self.session.request(method, - conn_url, - **kwargs) - - # TODO(deva): implement graceful client downgrade when connecting - # to servers that did not support microversions. Details here: - # https://specs.openstack.org/openstack/ironic-specs/specs/kilo-implemented/api-microversions.html#use-case-3b-new-client-communicating-with-a-old-ironic-user-specified # noqa - - if resp.status_code == http_client.NOT_ACCEPTABLE: - negotiated_ver = self.negotiate_version(self.session, resp) - kwargs['headers']['X-OpenStack-Ironic-API-Version'] = ( - negotiated_ver) - return self._http_request(url, method, **kwargs) - - except requests.exceptions.RequestException as e: - message = (_("Error has occurred while handling " - "request for %(url)s: %(e)s") % - dict(url=conn_url, e=e)) - # NOTE(aarefiev): not valid request(invalid url, missing schema, - # and so on), retrying is not needed. - if isinstance(e, ValueError): - raise exc.ValidationError(message) - - raise exc.ConnectionRefused(message) - - body_str = None - if resp.headers.get('Content-Type') == 'application/octet-stream': - body_iter = resp.iter_content(chunk_size=CHUNKSIZE) - self.log_http_response(resp) - else: - # Read body into string if it isn't obviously image data - body_str = resp.text - self.log_http_response(resp, body_str) - body_iter = six.StringIO(body_str) - - if resp.status_code >= http_client.BAD_REQUEST: - error_json = _extract_error_json(body_str) - # NOTE(vdrok): exceptions from ironic controllers' _lookup methods - # are constructed directly by pecan instead of wsme, and contain - # only description field - raise exc.from_response( - resp, (error_json.get('faultstring') or - error_json.get('description')), - error_json.get('debuginfo'), method, url) - elif resp.status_code in (http_client.MOVED_PERMANENTLY, - http_client.FOUND, - http_client.USE_PROXY): - # Redirected. Reissue the request to the new location. - return self._http_request(resp['location'], method, **kwargs) - elif resp.status_code == http_client.MULTIPLE_CHOICES: - raise exc.from_response(resp, method=method, url=url) - - return resp, body_iter - - def json_request(self, method, url, **kwargs): - kwargs.setdefault('headers', {}) - kwargs['headers'].setdefault('Content-Type', 'application/json') - kwargs['headers'].setdefault('Accept', 'application/json') - - if 'body' in kwargs: - kwargs['body'] = jsonutils.dump_as_bytes(kwargs['body']) - - resp, body_iter = self._http_request(url, method, **kwargs) - content_type = resp.headers.get('Content-Type') - - if (resp.status_code in (http_client.NO_CONTENT, - http_client.RESET_CONTENT) - or content_type is None): - return resp, list() - - if 'application/json' in content_type: - body = ''.join([chunk for chunk in body_iter]) - try: - body = jsonutils.loads(body) - except ValueError: - LOG.error('Could not decode response body as JSON') - else: - body = None - - return resp, body - - def raw_request(self, method, url, **kwargs): - kwargs.setdefault('headers', {}) - kwargs['headers'].setdefault('Content-Type', - 'application/octet-stream') - return self._http_request(url, method, **kwargs) - - -class VerifiedHTTPSConnection(six.moves.http_client.HTTPSConnection): - """httplib-compatible connection using client-side SSL authentication - - :see http://code.activestate.com/recipes/ - 577548-https-httplib-client-connection-with-certificate-v/ - """ - - def __init__(self, host, port, key_file=None, cert_file=None, - ca_file=None, timeout=None, insecure=False): - six.moves.http_client.HTTPSConnection.__init__(self, host, port, - key_file=key_file, - cert_file=cert_file) - self.key_file = key_file - self.cert_file = cert_file - if ca_file is not None: - self.ca_file = ca_file - else: - self.ca_file = self.get_system_ca_file() - self.timeout = timeout - self.insecure = insecure - - def connect(self): - """Connect to a host on a given (SSL) port. - - If ca_file is pointing somewhere, use it to check Server Certificate. - - Redefined/copied and extended from httplib.py:1105 (Python 2.6.x). - This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter to - ssl.wrap_socket(), which forces SSL to check server certificate against - our client certificate. - """ - sock = socket.create_connection((self.host, self.port), self.timeout) - - if self._tunnel_host: - self.sock = sock - self._tunnel() - - if self.insecure is True: - kwargs = {'cert_reqs': ssl.CERT_NONE} - else: - kwargs = {'cert_reqs': ssl.CERT_REQUIRED, 'ca_certs': self.ca_file} - - if self.cert_file: - kwargs['certfile'] = self.cert_file - if self.key_file: - kwargs['keyfile'] = self.key_file - - self.sock = ssl.wrap_socket(sock, **kwargs) - - @staticmethod - def get_system_ca_file(): - """Return path to system default CA file.""" - # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora, - # Suse, FreeBSD/OpenBSD - ca_path = ['/etc/ssl/certs/ca-certificates.crt', - '/etc/pki/tls/certs/ca-bundle.crt', - '/etc/ssl/ca-bundle.pem', - '/etc/ssl/cert.pem'] - for ca in ca_path: - if os.path.exists(ca): - return ca - return None - - -class SessionClient(VersionNegotiationMixin, adapter.LegacyJsonAdapter): - """HTTP client based on Keystone client session.""" - - def __init__(self, - os_ironic_api_version, - api_version_select_state, - max_retries, - retry_interval, - endpoint, - **kwargs): - self.os_ironic_api_version = os_ironic_api_version - self.api_version_select_state = api_version_select_state - self.conflict_max_retries = max_retries - self.conflict_retry_interval = retry_interval - self.endpoint = endpoint - - super(SessionClient, self).__init__(**kwargs) - - def _parse_version_headers(self, resp): - return self._generic_parse_version_headers(resp.headers.get) - - def _make_simple_request(self, conn, method, url): - # NOTE: conn is self.session for this class - return conn.request(url, method, raise_exc=False) - - @with_retries - def _http_request(self, url, method, **kwargs): - kwargs.setdefault('user_agent', USER_AGENT) - kwargs.setdefault('auth', self.auth) - if isinstance(self.endpoint_override, six.string_types): - kwargs.setdefault( - 'endpoint_override', - _trim_endpoint_api_version(self.endpoint_override) - ) - - if getattr(self, 'os_ironic_api_version', None): - kwargs['headers'].setdefault('X-OpenStack-Ironic-API-Version', - self.os_ironic_api_version) - - endpoint_filter = kwargs.setdefault('endpoint_filter', {}) - endpoint_filter.setdefault('interface', self.interface) - endpoint_filter.setdefault('service_type', self.service_type) - endpoint_filter.setdefault('region_name', self.region_name) - - resp = self.session.request(url, method, - raise_exc=False, **kwargs) - if resp.status_code == http_client.NOT_ACCEPTABLE: - negotiated_ver = self.negotiate_version(self.session, resp) - kwargs['headers']['X-OpenStack-Ironic-API-Version'] = ( - negotiated_ver) - return self._http_request(url, method, **kwargs) - if resp.status_code >= http_client.BAD_REQUEST: - error_json = _extract_error_json(resp.content) - # NOTE(vdrok): exceptions from ironic controllers' _lookup methods - # are constructed directly by pecan instead of wsme, and contain - # only description field - raise exc.from_response(resp, (error_json.get('faultstring') or - error_json.get('description')), - error_json.get('debuginfo'), method, url) - elif resp.status_code in (http_client.MOVED_PERMANENTLY, - http_client.FOUND, http_client.USE_PROXY): - # Redirected. Reissue the request to the new location. - location = resp.headers.get('location') - resp = self._http_request(location, method, **kwargs) - elif resp.status_code == http_client.MULTIPLE_CHOICES: - raise exc.from_response(resp, method=method, url=url) - return resp - - def json_request(self, method, url, **kwargs): - kwargs.setdefault('headers', {}) - kwargs['headers'].setdefault('Content-Type', 'application/json') - kwargs['headers'].setdefault('Accept', 'application/json') - - if 'body' in kwargs: - kwargs['data'] = jsonutils.dump_as_bytes(kwargs.pop('body')) - - resp = self._http_request(url, method, **kwargs) - body = resp.content - content_type = resp.headers.get('content-type', None) - status = resp.status_code - if (status in (http_client.NO_CONTENT, http_client.RESET_CONTENT) or - content_type is None): - return resp, list() - if 'application/json' in content_type: - try: - body = resp.json() - except ValueError: - LOG.error('Could not decode response body as JSON') - else: - body = None - - return resp, body - - def raw_request(self, method, url, **kwargs): - kwargs.setdefault('headers', {}) - kwargs['headers'].setdefault('Content-Type', - 'application/octet-stream') - return self._http_request(url, method, **kwargs) - - -def _construct_http_client(endpoint=None, - session=None, - token=None, - auth_ref=None, - os_ironic_api_version=DEFAULT_VER, - api_version_select_state='default', - max_retries=DEFAULT_MAX_RETRIES, - retry_interval=DEFAULT_RETRY_INTERVAL, - timeout=600, - ca_file=None, - cert_file=None, - key_file=None, - insecure=None, - **kwargs): - if session: - kwargs.setdefault('service_type', 'baremetal') - kwargs.setdefault('user_agent', 'python-ironicclient') - kwargs.setdefault('interface', kwargs.pop('endpoint_type', None)) - kwargs.setdefault('endpoint_override', endpoint) - - ignored = {'token': token, - 'auth_ref': auth_ref, - 'timeout': timeout != 600, - 'ca_file': ca_file, - 'cert_file': cert_file, - 'key_file': key_file, - 'insecure': insecure} - - dvars = [k for k, v in ignored.items() if v] - - if dvars: - LOG.warning('The following arguments are ignored when using ' - 'the session to construct a client: %s', - ', '.join(dvars)) - - return SessionClient(session=session, - os_ironic_api_version=os_ironic_api_version, - api_version_select_state=api_version_select_state, - max_retries=max_retries, - retry_interval=retry_interval, - endpoint=endpoint, - **kwargs) - else: - if kwargs: - LOG.warning('The following arguments are being ignored when ' - 'constructing the client: %s'), ', '.join(kwargs) - - return HTTPClient(endpoint=endpoint, - token=token, - auth_ref=auth_ref, - os_ironic_api_version=os_ironic_api_version, - api_version_select_state=api_version_select_state, - max_retries=max_retries, - retry_interval=retry_interval, - timeout=timeout, - ca_file=ca_file, - cert_file=cert_file, - key_file=key_file, - insecure=insecure) diff --git a/ironicclient/common/i18n.py b/ironicclient/common/i18n.py deleted file mode 100644 index 90f289a..0000000 --- a/ironicclient/common/i18n.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# 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 oslo_i18n - -_translators = oslo_i18n.TranslatorFactory(domain='ironicclient') - -# The primary translation function using the well-known name "_" -_ = _translators.primary diff --git a/ironicclient/common/utils.py b/ironicclient/common/utils.py deleted file mode 100644 index 0f3038b..0000000 --- a/ironicclient/common/utils.py +++ /dev/null @@ -1,393 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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 __future__ import print_function - -import argparse -import contextlib -import gzip -import json -import os -import shutil -import subprocess -import sys -import tempfile - -from oslo_serialization import base64 -from oslo_utils import strutils -import six - -from ironicclient.common.i18n import _ -from ironicclient import exc - - -class HelpFormatter(argparse.HelpFormatter): - def start_section(self, heading): - super(HelpFormatter, self).start_section(heading.capitalize()) - - -def define_command(subparsers, command, callback, cmd_mapper): - """Define a command in the subparsers collection. - - :param subparsers: subparsers collection where the command will go - :param command: command name - :param callback: function that will be used to process the command - """ - desc = callback.__doc__ or '' - help = desc.strip().split('\n')[0] - arguments = getattr(callback, 'arguments', []) - - subparser = subparsers.add_parser(command, help=help, - description=desc, - add_help=False, - formatter_class=HelpFormatter) - subparser.add_argument('-h', '--help', action='help', - help=argparse.SUPPRESS) - cmd_mapper[command] = subparser - required_args = subparser.add_argument_group(_("Required arguments")) - - for (args, kwargs) in arguments: - if kwargs.get('required'): - required_args.add_argument(*args, **kwargs) - else: - subparser.add_argument(*args, **kwargs) - subparser.set_defaults(func=callback) - - -def define_commands_from_module(subparsers, command_module, cmd_mapper): - """Add *do_* methods in a module and add as commands into a subparsers.""" - - for method_name in (a for a in dir(command_module) if a.startswith('do_')): - # Commands should be hypen-separated instead of underscores. - command = method_name[3:].replace('_', '-') - callback = getattr(command_module, method_name) - define_command(subparsers, command, callback, cmd_mapper) - - -def split_and_deserialize(string): - """Split and try to JSON deserialize a string. - - Gets a string with the KEY=VALUE format, split it (using '=' as the - separator) and try to JSON deserialize the VALUE. - - :returns: A tuple of (key, value). - """ - try: - key, value = string.split("=", 1) - except ValueError: - raise exc.CommandError(_('Attributes must be a list of ' - 'PATH=VALUE not "%s"') % string) - try: - value = json.loads(value) - except ValueError: - pass - - return (key, value) - - -def key_value_pairs_to_dict(key_value_pairs): - """Convert a list of key-value pairs to a dictionary. - - :param key_value_pairs: a list of strings, each string is in the form - = - :returns: a dictionary, possibly empty - """ - if key_value_pairs: - return dict(split_and_deserialize(v) for v in key_value_pairs) - return {} - - -def args_array_to_dict(kwargs, key_to_convert): - """Convert the value in a dictionary entry to a dictionary. - - From the kwargs dictionary, converts the value of the key_to_convert - entry from a list of key-value pairs to a dictionary. - - :param kwargs: a dictionary - :param key_to_convert: the key (in kwargs), whose value is expected to - be a list of key=value strings. This value will be converted to a - dictionary. - :returns: kwargs, the (modified) dictionary - """ - values_to_convert = kwargs.get(key_to_convert) - if values_to_convert: - kwargs[key_to_convert] = key_value_pairs_to_dict(values_to_convert) - return kwargs - - -def args_array_to_patch(op, attributes): - patch = [] - for attr in attributes: - # Sanitize - if not attr.startswith('/'): - attr = '/' + attr - - if op in ['add', 'replace']: - path, value = split_and_deserialize(attr) - patch.append({'op': op, 'path': path, 'value': value}) - - elif op == "remove": - # For remove only the key is needed - patch.append({'op': op, 'path': attr}) - else: - raise exc.CommandError(_('Unknown PATCH operation: %s') % op) - return patch - - -def convert_list_props_to_comma_separated(data, props=None): - """Convert the list-type properties to comma-separated strings - - :param data: the input dict object. - :param props: the properties whose values will be converted. - Default to None to convert all list-type properties of the input. - :returns: the result dict instance. - """ - result = dict(data) - - if props is None: - props = data.keys() - - for prop in props: - val = data.get(prop, None) - if isinstance(val, list): - result[prop] = ', '.join(map(six.text_type, val)) - - return result - - -def common_params_for_list(args, fields, field_labels): - """Generate 'params' dict that is common for every 'list' command. - - :param args: arguments from command line. - :param fields: possible fields for sorting. - :param field_labels: possible field labels for sorting. - :returns: a dict with params to pass to the client method. - """ - params = {} - if args.marker is not None: - params['marker'] = args.marker - if args.limit is not None: - if args.limit < 0: - raise exc.CommandError( - _('Expected non-negative --limit, got %s') % args.limit) - params['limit'] = args.limit - - if args.sort_key is not None: - # Support using both heading and field name for sort_key - fields_map = dict(zip(field_labels, fields)) - fields_map.update(zip(fields, fields)) - try: - sort_key = fields_map[args.sort_key] - except KeyError: - raise exc.CommandError( - _("%(sort_key)s is an invalid field for sorting, " - "valid values for --sort-key are: %(valid)s") % - {'sort_key': args.sort_key, - 'valid': list(fields_map)}) - params['sort_key'] = sort_key - if args.sort_dir is not None: - if args.sort_dir not in ('asc', 'desc'): - raise exc.CommandError( - _("%s is an invalid value for sort direction, " - "valid values for --sort-dir are: 'asc', 'desc'") % - args.sort_dir) - params['sort_dir'] = args.sort_dir - - params['detail'] = args.detail - - requested_fields = args.fields[0] if args.fields else None - if requested_fields is not None: - params['fields'] = requested_fields - - return params - - -def common_filters(marker=None, limit=None, sort_key=None, sort_dir=None, - fields=None, detail=False): - """Generate common filters for any list request. - - :param marker: entity ID from which to start returning entities. - :param limit: maximum number of entities to return. - :param sort_key: field to use for sorting. - :param sort_dir: direction of sorting: 'asc' or 'desc'. - :param fields: a list with a specified set of fields of the resource - to be returned. - :param detail: Boolean, True to return detailed information. This parameter - can be used for resources which accept 'detail' as a URL - parameter. - :returns: list of string filters. - """ - filters = [] - if isinstance(limit, int) and limit > 0: - filters.append('limit=%s' % limit) - if marker is not None: - filters.append('marker=%s' % marker) - if sort_key is not None: - filters.append('sort_key=%s' % sort_key) - if sort_dir is not None: - filters.append('sort_dir=%s' % sort_dir) - if fields is not None: - filters.append('fields=%s' % ','.join(fields)) - if detail: - filters.append('detail=True') - return filters - - -@contextlib.contextmanager -def tempdir(*args, **kwargs): - dirname = tempfile.mkdtemp(*args, **kwargs) - try: - yield dirname - finally: - shutil.rmtree(dirname) - - -def make_configdrive(path): - """Make the config drive file. - - :param path: The directory containing the config drive files. - :returns: A gzipped and base64 encoded configdrive string. - - """ - # Make sure path it's readable - if not os.access(path, os.R_OK): - raise exc.CommandError(_('The directory "%s" is not readable') % path) - - with tempfile.NamedTemporaryFile() as tmpfile: - with tempfile.NamedTemporaryFile() as tmpzipfile: - publisher = 'ironicclient-configdrive 0.1' - try: - p = subprocess.Popen(['genisoimage', '-o', tmpfile.name, - '-ldots', '-allow-lowercase', - '-allow-multidot', '-l', - '-publisher', publisher, - '-quiet', '-J', - '-r', '-V', 'config-2', - path], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - except OSError as e: - raise exc.CommandError( - _('Error generating the config drive. Make sure the ' - '"genisoimage" tool is installed. Error: %s') % e) - - stdout, stderr = p.communicate() - if p.returncode != 0: - raise exc.CommandError( - _('Error generating the config drive.' - 'Stdout: "%(stdout)s". Stderr: %(stderr)s') % - {'stdout': stdout, 'stderr': stderr}) - - # Compress file - tmpfile.seek(0) - g = gzip.GzipFile(fileobj=tmpzipfile, mode='wb') - shutil.copyfileobj(tmpfile, g) - g.close() - - tmpzipfile.seek(0) - return base64.encode_as_bytes(tmpzipfile.read()) - - -def check_empty_arg(arg, arg_descriptor): - if not arg.strip(): - raise exc.CommandError(_('%(arg)s cannot be empty or only have blank' - ' spaces') % {'arg': arg_descriptor}) - - -def bool_argument_value(arg_name, bool_str, strict=True, default=False): - """Returns the Boolean represented by bool_str. - - Returns the Boolean value for the argument named arg_name. The value is - represented by the string bool_str. If the string is an invalid Boolean - string: if strict is True, a CommandError exception is raised; otherwise - the default value is returned. - - :param arg_name: The name of the argument - :param bool_str: The string representing a Boolean value - :param strict: Used if the string is invalid. If True, raises an exception. - If False, returns the default value. - :param default: The default value to return if the string is invalid - and not strict - :returns: the Boolean value represented by bool_str or the default value - if bool_str is invalid and strict is False - :raises CommandError: if bool_str is an invalid Boolean string - - """ - try: - val = strutils.bool_from_string(bool_str, strict, default) - except ValueError as e: - raise exc.CommandError(_("argument %(arg)s: %(err)s.") - % {'arg': arg_name, 'err': e}) - return val - - -def check_for_invalid_fields(fields, valid_fields): - """Check for invalid fields. - - :param fields: A list of fields specified by the user. - :param valid_fields: A list of valid fields. - :raises CommandError: If invalid fields were specified by the user. - """ - if not fields: - return - - invalid_fields = set(fields) - set(valid_fields) - if invalid_fields: - raise exc.CommandError( - _('Invalid field(s) requested: %(invalid)s. Valid fields ' - 'are: %(valid)s.') % {'invalid': ', '.join(invalid_fields), - 'valid': ', '.join(valid_fields)}) - - -def get_from_stdin(info_desc): - """Read information from stdin. - - :param info_desc: A string description of the desired information - :raises: InvalidAttribute if there was a problem reading from stdin - :returns: the string that was read from stdin - """ - try: - info = sys.stdin.read().strip() - except Exception as e: - err = _("Cannot get %(desc)s from standard input. Error: %(err)s") - raise exc.InvalidAttribute(err % {'desc': info_desc, 'err': e}) - return info - - -def handle_json_or_file_arg(json_arg): - """Attempts to read JSON argument from file or string. - - :param json_arg: May be a file name containing the JSON, or - a JSON string. - :returns: A list or dictionary parsed from JSON. - :raises: InvalidAttribute if the argument cannot be parsed. - """ - - if os.path.isfile(json_arg): - try: - with open(json_arg, 'r') as f: - json_arg = f.read().strip() - except Exception as e: - err = _("Cannot get JSON from file '%(file)s'. " - "Error: %(err)s") % {'err': e, 'file': json_arg} - raise exc.InvalidAttribute(err) - try: - json_arg = json.loads(json_arg) - except ValueError as e: - err = (_("For JSON: '%(string)s', error: '%(err)s'") % - {'err': e, 'string': json_arg}) - raise exc.InvalidAttribute(err) - - return json_arg diff --git a/ironicclient/exc.py b/ironicclient/exc.py deleted file mode 100644 index 85caf01..0000000 --- a/ironicclient/exc.py +++ /dev/null @@ -1,71 +0,0 @@ -# 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 ironicclient.common.apiclient import exceptions -from ironicclient.common.apiclient.exceptions import * # noqa - - -# NOTE(akurilin): This alias is left here since v.0.1.3 to support backwards -# compatibility. -InvalidEndpoint = EndpointException -CommunicationError = ConnectionRefused -HTTPBadRequest = BadRequest -HTTPInternalServerError = InternalServerError -HTTPNotFound = NotFound -HTTPServiceUnavailable = ServiceUnavailable - - -class AmbiguousAuthSystem(ClientException): - """Could not obtain token and endpoint using provided credentials.""" - pass - -# Alias for backwards compatibility -AmbigiousAuthSystem = AmbiguousAuthSystem - - -class InvalidAttribute(ClientException): - pass - - -class StateTransitionFailed(ClientException): - """Failed to reach a requested provision state.""" - - -class StateTransitionTimeout(ClientException): - """Timed out while waiting for a requested provision state.""" - - -def from_response(response, message=None, traceback=None, method=None, - url=None): - """Return an HttpError instance based on response from httplib/requests.""" - - error_body = {} - if message: - error_body['message'] = message - if traceback: - error_body['details'] = traceback - - if hasattr(response, 'status') and not hasattr(response, 'status_code'): - # NOTE(akurilin): These modifications around response object give - # ability to get all necessary information in method `from_response` - # from common code, which expecting response object from `requests` - # library instead of object from `httplib/httplib2` library. - response.status_code = response.status - response.headers = { - 'Content-Type': response.getheader('content-type', "")} - - if hasattr(response, 'status_code'): - # NOTE(jiangfei): These modifications allow SessionClient - # to handle faultstring. - response.json = lambda: {'error': error_body} - - return exceptions.from_response(response, method=method, url=url) diff --git a/ironicclient/osc/__init__.py b/ironicclient/osc/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/osc/plugin.py b/ironicclient/osc/plugin.py deleted file mode 100644 index e1f9764..0000000 --- a/ironicclient/osc/plugin.py +++ /dev/null @@ -1,105 +0,0 @@ -# -# Copyright 2015 Red Hat, Inc. -# -# 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. -# - -"""OpenStackClient plugin for Bare Metal service.""" - -import argparse -import logging - -from ironicclient.common import http -from osc_lib import utils - -LOG = logging.getLogger(__name__) - -API_VERSION_OPTION = 'os_baremetal_api_version' -API_NAME = 'baremetal' -LAST_KNOWN_API_VERSION = 34 -API_VERSIONS = { - '1.%d' % i: 'ironicclient.v1.client.Client' - for i in range(1, LAST_KNOWN_API_VERSION + 1) -} -API_VERSIONS['1'] = API_VERSIONS[http.DEFAULT_VER] -OS_BAREMETAL_API_VERSION_SPECIFIED = False -MISSING_VERSION_WARNING = ( - "You are using the default API version of the OpenStack CLI baremetal " - "(ironic) plugin. This is currently API version %s. In the future, " - "the default will be the latest API version understood by both API " - "and CLI. You can preserve the current behavior by passing the " - "--os-baremetal-api-version argument with the desired version or using " - "the OS_BAREMETAL_API_VERSION environment variable." -) - - -def make_client(instance): - """Returns a baremetal service client.""" - if (not OS_BAREMETAL_API_VERSION_SPECIFIED and not - utils.env('OS_BAREMETAL_API_VERSION')): - LOG.warning(MISSING_VERSION_WARNING, http.DEFAULT_VER) - - baremetal_client_class = utils.get_client_class( - API_NAME, - instance._api_version[API_NAME], - API_VERSIONS) - LOG.debug('Instantiating baremetal client: %s', baremetal_client_class) - LOG.debug('Baremetal API version: %s', http.DEFAULT_VER) - - client = baremetal_client_class( - os_ironic_api_version=instance._api_version[API_NAME], - session=instance.session, - region_name=instance._region_name, - # NOTE(vdrok): This will be set as endpoint_override, and the Client - # class will be able to do the version stripping if needed - endpoint=instance.get_endpoint_for_service_type( - API_NAME, interface=instance.interface, - region_name=instance._region_name - ) - ) - return client - - -def build_option_parser(parser): - """Hook to add global options.""" - parser.add_argument( - '--os-baremetal-api-version', - metavar='', - default=utils.env( - 'OS_BAREMETAL_API_VERSION', - default=http.DEFAULT_VER), - choices=sorted( - API_VERSIONS, - key=lambda k: [int(x) for x in k.split('.')]) + ['latest'], - action=ReplaceLatestVersion, - help='Baremetal API version, default=' + - http.DEFAULT_VER + - ' (Env: OS_BAREMETAL_API_VERSION). ' - 'Use "latest" for the latest known API version. ' - 'The default value will change to "latest" in the Queens ' - 'release.', - ) - return parser - - -class ReplaceLatestVersion(argparse.Action): - """Replaces `latest` keyword by last known version.""" - def __call__(self, parser, namespace, values, option_string=None): - global OS_BAREMETAL_API_VERSION_SPECIFIED - OS_BAREMETAL_API_VERSION_SPECIFIED = True - latest = values == 'latest' - if latest: - values = '1.%d' % LAST_KNOWN_API_VERSION - LOG.debug("Replacing 'latest' API version with the " - "latest known version '%s'", values) - setattr(namespace, self.dest, values) diff --git a/ironicclient/osc/v1/__init__.py b/ironicclient/osc/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/osc/v1/baremetal_chassis.py b/ironicclient/osc/v1/baremetal_chassis.py deleted file mode 100644 index a84fc52..0000000 --- a/ironicclient/osc/v1/baremetal_chassis.py +++ /dev/null @@ -1,325 +0,0 @@ -# -# Copyright 2016 Intel Corporation -# -# 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 itertools -import logging - -from osc_lib.command import command -from osc_lib import utils as oscutils - -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.v1 import resource_fields as res_fields - - -class CreateBaremetalChassis(command.ShowOne): - """Create a new chassis.""" - - log = logging.getLogger(__name__ + ".CreateBaremetalChassis") - - def get_parser(self, prog_name): - parser = super(CreateBaremetalChassis, self).get_parser(prog_name) - - parser.add_argument( - '--description', - dest='description', - metavar='', - help=_('Description for the chassis') - ) - parser.add_argument( - '--extra', - metavar='', - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.") - ) - parser.add_argument( - '--uuid', - metavar='', - help=_("Unique UUID of the chassis") - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - field_list = ['description', 'extra', 'uuid'] - fields = dict((k, v) for (k, v) in vars(parsed_args).items() - if k in field_list and not (v is None)) - fields = utils.args_array_to_dict(fields, 'extra') - chassis = baremetal_client.chassis.create(**fields)._info - - chassis.pop('links', None) - chassis.pop('nodes', None) - - return self.dict2columns(chassis) - - -class DeleteBaremetalChassis(command.Command): - """Delete a chassis.""" - - log = logging.getLogger(__name__ + ".DeleteBaremetalChassis") - - def get_parser(self, prog_name): - parser = super(DeleteBaremetalChassis, self).get_parser(prog_name) - parser.add_argument( - "chassis", - metavar="", - nargs="+", - help=_("UUIDs of chassis to delete") - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - failures = [] - for chassis in parsed_args.chassis: - try: - baremetal_client.chassis.delete(chassis) - print(_('Deleted chassis %s') % chassis) - except exc.ClientException as e: - failures.append(_("Failed to delete chassis %(chassis)s: " - "%(error)s") - % {'chassis': chassis, 'error': e}) - - if failures: - raise exc.ClientException("\n".join(failures)) - - -class ListBaremetalChassis(command.Lister): - """List the chassis.""" - - log = logging.getLogger(__name__ + ".ListBaremetalChassis") - - def get_parser(self, prog_name): - parser = super(ListBaremetalChassis, self).get_parser(prog_name) - display_group = parser.add_mutually_exclusive_group(required=False) - display_group.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - choices=res_fields.CHASSIS_DETAILED_RESOURCE.fields, - help=_("One or more chassis fields. Only these fields will be " - "fetched from the server. Cannot be used when '--long' is " - "specified.") - ) - parser.add_argument( - '--limit', - metavar='', - type=int, - help=_('Maximum number of chassis to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Baremetal API Service.') - ) - display_group.add_argument( - '--long', - default=False, - action='store_true', - help=_("Show detailed information about the chassis") - ) - parser.add_argument( - '--marker', - metavar='', - help=_('Chassis UUID (for example, of the last chassis in the ' - 'list from a previous request). Returns the list of ' - 'chassis after this UUID.') - ) - parser.add_argument( - '--sort', - metavar="[:]", - help=_('Sort output by specified chassis fields and directions ' - '(asc or desc) (default: asc). Multiple fields and ' - 'directions can be specified, separated by comma.') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - client = self.app.client_manager.baremetal - - columns = res_fields.CHASSIS_RESOURCE.fields - labels = res_fields.CHASSIS_RESOURCE.labels - - params = {} - if parsed_args.limit is not None and parsed_args.limit < 0: - raise exc.CommandError( - _('Expected non-negative --limit, got %s') % - parsed_args.limit) - params['limit'] = parsed_args.limit - params['marker'] = parsed_args.marker - if parsed_args.long: - params['detail'] = parsed_args.long - columns = res_fields.CHASSIS_DETAILED_RESOURCE.fields - labels = res_fields.CHASSIS_DETAILED_RESOURCE.labels - elif parsed_args.fields: - params['detail'] = False - fields = itertools.chain.from_iterable(parsed_args.fields) - resource = res_fields.Resource(list(fields)) - columns = resource.fields - labels = resource.labels - params['fields'] = columns - - self.log.debug("params(%s)", params) - data = client.chassis.list(**params) - - data = oscutils.sort_items(data, parsed_args.sort) - - return (labels, - (oscutils.get_item_properties(s, columns, formatters={ - 'Properties': oscutils.format_dict},) for s in data)) - - -class SetBaremetalChassis(command.Command): - """Set chassis properties.""" - - log = logging.getLogger(__name__ + ".SetBaremetalChassis") - - def get_parser(self, prog_name): - parser = super(SetBaremetalChassis, self).get_parser(prog_name) - - parser.add_argument( - 'chassis', - metavar='', - help=_("UUID of the chassis") - ) - parser.add_argument( - "--description", - metavar="", - help=_("Set the description of the chassis") - ) - parser.add_argument( - "--extra", - metavar="", - action='append', - help=_('Extra to set on this chassis ' - '(repeat option to set multiple extras)') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - properties = [] - if parsed_args.description: - description = ["description=%s" % parsed_args.description] - properties.extend(utils.args_array_to_patch( - 'add', description)) - if parsed_args.extra: - properties.extend(utils.args_array_to_patch( - 'add', ['extra/' + x for x in parsed_args.extra])) - - if properties: - baremetal_client.chassis.update(parsed_args.chassis, properties) - else: - self.log.warning("Please specify what to set.") - - -class ShowBaremetalChassis(command.ShowOne): - """Show chassis details.""" - - log = logging.getLogger(__name__ + ".ShowBaremetalChassis") - - def get_parser(self, prog_name): - parser = super(ShowBaremetalChassis, self).get_parser(prog_name) - parser.add_argument( - "chassis", - metavar="", - help=_("UUID of the chassis") - ) - parser.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - choices=res_fields.CHASSIS_DETAILED_RESOURCE.fields, - default=[], - help=_("One or more chassis fields. Only these fields will be " - "fetched from the server.") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - fields = list(itertools.chain.from_iterable(parsed_args.fields)) - fields = fields if fields else None - chassis = baremetal_client.chassis.get(parsed_args.chassis, - fields=fields)._info - chassis.pop("links", None) - chassis.pop("nodes", None) - - return zip(*sorted(chassis.items())) - - -class UnsetBaremetalChassis(command.Command): - """Unset chassis properties.""" - log = logging.getLogger(__name__ + ".UnsetBaremetalChassis") - - def get_parser(self, prog_name): - parser = super(UnsetBaremetalChassis, self).get_parser(prog_name) - - parser.add_argument( - 'chassis', - metavar='', - help=_("UUID of the chassis") - ) - parser.add_argument( - '--description', - action='store_true', - default=False, - help=_('Clear the chassis description') - ) - parser.add_argument( - "--extra", - metavar="", - action='append', - help=_('Extra to unset on this chassis ' - '(repeat option to unset multiple extras)') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - properties = [] - if parsed_args.description: - properties.extend(utils.args_array_to_patch('remove', - ['description'])) - if parsed_args.extra: - properties.extend(utils.args_array_to_patch('remove', - ['extra/' + x for x in parsed_args.extra])) - - if properties: - baremetal_client.chassis.update(parsed_args.chassis, properties) - else: - self.log.warning("Please specify what to unset.") diff --git a/ironicclient/osc/v1/baremetal_create.py b/ironicclient/osc/v1/baremetal_create.py deleted file mode 100644 index c16db10..0000000 --- a/ironicclient/osc/v1/baremetal_create.py +++ /dev/null @@ -1,78 +0,0 @@ -# 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 argparse -import logging - -from ironicclient.common.i18n import _ -from ironicclient import exc -from ironicclient.osc.v1 import baremetal_node -from ironicclient.v1 import create_resources - - -class CreateBaremetal(baremetal_node.CreateBaremetalNode): - """Create resources from files or Register a new node (DEPRECATED). - - Create resources from files (by only specifying the files) or register - a new node by specifying one or more optional arguments (DEPRECATED, - use 'openstack baremetal node create' instead). - """ - - log = logging.getLogger(__name__ + ".CreateBaremetal") - - def get_description(self): - return _("Create resources from files (by only specifying the files) " - "or register a new node by specifying one or more optional " - "arguments (DEPRECATED, use 'openstack baremetal node " - "create' instead)") - - # TODO(vdrok): Remove support for new node creation after 11-July-2017 - # during the 'Queens' cycle. - def get_parser(self, prog_name): - parser = super(CreateBaremetal, self).get_parser(prog_name) - # NOTE(vdrok): It is a workaround to allow --driver to be optional for - # openstack create command while creation of nodes via this command is - # not removed completely - parser = argparse.ArgumentParser(parents=[parser], - conflict_handler='resolve', - description=self.__doc__) - parser.add_argument( - '--driver', - metavar='', - help=_('Specify this and any other optional arguments if you want ' - 'to create a node only. Note that this is deprecated; ' - 'please use "openstack baremetal node create" instead.')) - parser.add_argument( - "resource_files", metavar="", default=[], nargs="*", - help=_("File (.yaml or .json) containing descriptions of the " - "resources to create. Can be specified multiple times. If " - "you want to create resources, only specify the files. Do " - "not specify any of the optional arguments.")) - return parser - - def take_action(self, parsed_args): - if parsed_args.driver: - self.log.warning("This command is deprecated. Instead, use " - "'openstack baremetal node create'.") - return super(CreateBaremetal, self).take_action(parsed_args) - if not parsed_args.resource_files: - raise exc.ValidationError(_( - "If --driver is not supplied to openstack create command, " - "it is considered that it will create ironic resources from " - "one or more .json or .yaml files, but no files provided.")) - create_resources.create_resources(self.app.client_manager.baremetal, - parsed_args.resource_files) - # NOTE(vdrok): CreateBaremetal is still inherited from ShowOne class, - # which requires the return value of the function to be of certain - # type, leave this workaround until creation of nodes is removed and - # then change it so that this inherits from command.Command - return tuple(), tuple() diff --git a/ironicclient/osc/v1/baremetal_driver.py b/ironicclient/osc/v1/baremetal_driver.py deleted file mode 100644 index 9c3323c..0000000 --- a/ironicclient/osc/v1/baremetal_driver.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - - -import logging - -from osc_lib.command import command -from osc_lib import utils as oscutils - -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient.v1 import resource_fields as res_fields -from ironicclient.v1 import utils as v1_utils - - -class ListBaremetalDriver(command.Lister): - """List the enabled drivers.""" - - log = logging.getLogger(__name__ + ".ListBaremetalDriver") - - def get_parser(self, prog_name): - parser = super(ListBaremetalDriver, self).get_parser(prog_name) - parser.add_argument( - '--type', - metavar='', - choices=["classic", "dynamic"], - help='Type of driver ("classic" or "dynamic"). ' - 'The default is to list all of them.' - ) - parser.add_argument( - '--long', - action='store_true', - default=None, - help="Show detailed information about the drivers.") - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - client = self.app.client_manager.baremetal - - params = {'driver_type': parsed_args.type, - 'detail': parsed_args.long} - if parsed_args.long: - labels = res_fields.DRIVER_DETAILED_RESOURCE.labels - columns = res_fields.DRIVER_DETAILED_RESOURCE.fields - else: - labels = res_fields.DRIVER_RESOURCE.labels - columns = res_fields.DRIVER_RESOURCE.fields - - drivers = client.driver.list(**params) - drivers = oscutils.sort_items(drivers, 'name') - - # For list-type properties, show the values as comma separated - # strings. It's easier to read. - data = [utils.convert_list_props_to_comma_separated(d._info) - for d in drivers] - - return (labels, - (oscutils.get_dict_properties(s, columns) for s in data)) - - -class ListBaremetalDriverProperty(command.Lister): - """List the driver properties.""" - - log = logging.getLogger(__name__ + ".ListBaremetalDriverProperty") - - def get_parser(self, prog_name): - parser = super(ListBaremetalDriverProperty, self).get_parser(prog_name) - parser.add_argument( - 'driver', - metavar='', - help='Name of the driver.') - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - baremetal_client = self.app.client_manager.baremetal - - driver_properties = baremetal_client.driver.properties( - parsed_args.driver) - labels = ['Property', 'Description'] - return labels, sorted(driver_properties.items()) - - -class ListBaremetalDriverRaidProperty(command.Lister): - """List a driver's RAID logical disk properties.""" - - log = logging.getLogger(__name__ + ".ListBaremetalDriverRaidProperty") - - def get_parser(self, prog_name): - parser = super(ListBaremetalDriverRaidProperty, self).get_parser( - prog_name) - parser.add_argument( - 'driver', - metavar='', - help='Name of the driver.') - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - baremetal_client = self.app.client_manager.baremetal - - raid_props = baremetal_client.driver.raid_logical_disk_properties( - parsed_args.driver) - labels = ['Property', 'Description'] - return labels, sorted(raid_props.items()) - - -class PassthruCallBaremetalDriver(command.ShowOne): - """Call a vendor passthru method for a driver.""" - - log = logging.getLogger(__name__ + ".PassthruCallBaremetalDriver") - - def get_parser(self, prog_name): - parser = super(PassthruCallBaremetalDriver, self).get_parser(prog_name) - parser.add_argument( - 'driver', - metavar='', - help=_('Name of the driver.') - ) - parser.add_argument( - 'method', - metavar='', - help=_("Vendor passthru method to be called.") - ) - parser.add_argument( - '--arg', - metavar='', - action='append', - help=_("Argument to pass to the passthru method (repeat option " - "to specify multiple arguments).") - ) - parser.add_argument( - '--http-method', - dest='http_method', - metavar='', - choices=v1_utils.HTTP_METHODS, - default='POST', - help=_("The HTTP method to use in the passthru request. One of " - "%s. Defaults to 'POST'.") % - oscutils.format_list(v1_utils.HTTP_METHODS) - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - baremetal_client = self.app.client_manager.baremetal - - arguments = utils.key_value_pairs_to_dict(parsed_args.arg) - response = (baremetal_client.driver. - vendor_passthru(parsed_args.driver, - parsed_args.method, - http_method=parsed_args.http_method, - args=arguments)) - - return self.dict2columns(response) - - -class PassthruListBaremetalDriver(command.Lister): - """List available vendor passthru methods for a driver.""" - - log = logging.getLogger(__name__ + ".PassthruListBaremetalDriver") - - def get_parser(self, prog_name): - parser = super(PassthruListBaremetalDriver, self).get_parser(prog_name) - parser.add_argument( - 'driver', - metavar='', - help=_('Name of the driver.')) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - baremetal_client = self.app.client_manager.baremetal - - columns = res_fields.VENDOR_PASSTHRU_METHOD_RESOURCE.fields - labels = res_fields.VENDOR_PASSTHRU_METHOD_RESOURCE.labels - - methods = baremetal_client.driver.get_vendor_passthru_methods( - parsed_args.driver) - - params = [] - for method, response in methods.items(): - response['name'] = method - http_methods = ', '.join(response['http_methods']) - response['http_methods'] = http_methods - params.append(response) - - return (labels, - (oscutils.get_dict_properties(s, columns) for s in params)) - - -class ShowBaremetalDriver(command.ShowOne): - """Show information about a driver.""" - - log = logging.getLogger(__name__ + ".ShowBaremetalDriver") - - def get_parser(self, prog_name): - parser = super(ShowBaremetalDriver, self).get_parser(prog_name) - parser.add_argument( - 'driver', - metavar='', - help=_('Name of the driver.')) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - baremetal_client = self.app.client_manager.baremetal - - driver = baremetal_client.driver.get(parsed_args.driver)._info - driver.pop("links", None) - driver.pop("properties", None) - # For list-type properties, show the values as comma separated - # strings. It's easier to read. - driver = utils.convert_list_props_to_comma_separated(driver) - return zip(*sorted(driver.items())) diff --git a/ironicclient/osc/v1/baremetal_node.py b/ironicclient/osc/v1/baremetal_node.py deleted file mode 100755 index 8b14621..0000000 --- a/ironicclient/osc/v1/baremetal_node.py +++ /dev/null @@ -1,1609 +0,0 @@ -# -# Copyright 2015 Red Hat, Inc. -# -# 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 argparse -import itertools -import logging - -from osc_lib.command import command -from osc_lib import utils as oscutils - -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.v1 import resource_fields as res_fields -from ironicclient.v1 import utils as v1_utils - - -class ProvisionStateBaremetalNode(command.Command): - """Base provision state class""" - - log = logging.getLogger(__name__ + ".ProvisionStateBaremetalNode") - - def get_parser(self, prog_name): - parser = super(ProvisionStateBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node.") - ) - parser.add_argument( - '--provision-state', - default=self.PROVISION_STATE, - required=False, - choices=[self.PROVISION_STATE], - help=argparse.SUPPRESS) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - clean_steps = getattr(parsed_args, 'clean_steps', None) - if clean_steps == '-': - clean_steps = utils.get_from_stdin('clean steps') - if clean_steps: - clean_steps = utils.handle_json_or_file_arg(clean_steps) - - config_drive = getattr(parsed_args, 'config_drive', None) - - baremetal_client.node.set_provision_state( - parsed_args.node, - parsed_args.provision_state, - configdrive=config_drive, - cleansteps=clean_steps) - - -class ProvisionStateWithWait(ProvisionStateBaremetalNode): - """Provision state class adding --wait flag.""" - - log = logging.getLogger(__name__ + ".ProvisionStateWithWait") - - def get_parser(self, prog_name): - parser = super(ProvisionStateWithWait, self).get_parser(prog_name) - - desired_state = v1_utils.PROVISION_ACTIONS.get( - self.PROVISION_STATE)['expected_state'] - parser.add_argument( - '--wait', - type=int, - dest='wait_timeout', - default=None, - metavar='', - const=0, - nargs='?', - help=_("Wait for a node to reach the desired state, %(state)s. " - "Optionally takes a timeout value (in seconds). The " - "default value is 0, meaning it will wait indefinitely.") % - {'state': desired_state}) - return parser - - def take_action(self, parsed_args): - super(ProvisionStateWithWait, self).take_action(parsed_args) - self.log.debug("take_action(%s)", parsed_args) - - if (parsed_args.wait_timeout is None): - return - - baremetal_client = self.app.client_manager.baremetal - wait_args = v1_utils.PROVISION_ACTIONS.get( - parsed_args.provision_state) - if wait_args is None: - # This should never happen in reality, but checking just in case - raise exc.CommandError( - _("'--wait is not supported for provision state '%s'") - % parsed_args.provision_state) - - print(_('Waiting for provision state %(state)s on node %(node)s') % - {'state': wait_args['expected_state'], 'node': parsed_args.node}) - - baremetal_client.node.wait_for_provision_state( - parsed_args.node, - timeout=parsed_args.wait_timeout, - **wait_args) - - -class AbortBaremetalNode(ProvisionStateBaremetalNode): - """Set provision state of baremetal node to 'abort'""" - - log = logging.getLogger(__name__ + ".AbortBaremetalNode") - PROVISION_STATE = 'abort' - - -class AdoptBaremetalNode(ProvisionStateWithWait): - """Set provision state of baremetal node to 'adopt'""" - - log = logging.getLogger(__name__ + ".AdoptBaremetalNode") - PROVISION_STATE = 'adopt' - - -class BootdeviceSetBaremetalNode(command.Command): - """Set the boot device for a node""" - - log = logging.getLogger(__name__ + ".BootdeviceSetBaremetalNode") - - def get_parser(self, prog_name): - parser = super(BootdeviceSetBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - parser.add_argument( - 'device', - metavar='', - choices=v1_utils.BOOT_DEVICES, - help=_("One of %s") % (oscutils.format_list(v1_utils.BOOT_DEVICES)) - ) - parser.add_argument( - '--persistent', - dest='persistent', - action='store_true', - default=False, - help=_("Make changes persistent for all future boots") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - baremetal_client.node.set_boot_device( - parsed_args.node, - parsed_args.device, - parsed_args.persistent) - - -class BootdeviceShowBaremetalNode(command.ShowOne): - """Show the boot device information for a node""" - - log = logging.getLogger(__name__ + ".BootdeviceShowBaremetalNode") - - def get_parser(self, prog_name): - parser = super(BootdeviceShowBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - parser.add_argument( - '--supported', - dest='supported', - action='store_true', - default=False, - help=_("Show the supported boot devices") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - if parsed_args.supported: - info = baremetal_client.node.get_supported_boot_devices( - parsed_args.node) - boot_device_list = info.get('supported_boot_devices', []) - info['supported_boot_devices'] = ', '.join(boot_device_list) - else: - info = baremetal_client.node.get_boot_device(parsed_args.node) - return zip(*sorted(info.items())) - - -class CleanBaremetalNode(ProvisionStateWithWait): - """Set provision state of baremetal node to 'clean'""" - - log = logging.getLogger(__name__ + ".CleanBaremetalNode") - PROVISION_STATE = 'clean' - - def get_parser(self, prog_name): - parser = super(CleanBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - '--clean-steps', - metavar='', - required=True, - default=None, - help=_("The clean steps in JSON format. May be the path to a file " - "containing the clean steps; OR '-', with the clean steps " - "being read from standard input; OR a string. The value " - "should be a list of clean-step dictionaries; each " - "dictionary should have keys 'interface' and 'step', and " - "optional key 'args'.")) - return parser - - -class ConsoleDisableBaremetalNode(command.Command): - """Disable console access for a node""" - - log = logging.getLogger(__name__ + ".ConsoleDisableBaremetalNode") - - def get_parser(self, prog_name): - parser = super(ConsoleDisableBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - baremetal_client.node.set_console_mode(parsed_args.node, False) - - -class ConsoleEnableBaremetalNode(command.Command): - """Enable console access for a node""" - - log = logging.getLogger(__name__ + ".ConsoleEnableBaremetalNode") - - def get_parser(self, prog_name): - parser = super(ConsoleEnableBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - baremetal_client.node.set_console_mode(parsed_args.node, True) - - -class ConsoleShowBaremetalNode(command.ShowOne): - """Show console information for a node""" - - log = logging.getLogger(__name__ + ".ConsoleShowBaremetalNode") - - def get_parser(self, prog_name): - parser = super(ConsoleShowBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - info = baremetal_client.node.get_console(parsed_args.node) - return zip(*sorted(info.items())) - - -class CreateBaremetalNode(command.ShowOne): - """Register a new node with the baremetal service""" - - log = logging.getLogger(__name__ + ".CreateBaremetalNode") - - def get_parser(self, prog_name): - parser = super(CreateBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - '--chassis-uuid', - dest='chassis_uuid', - metavar='', - help=_('UUID of the chassis that this node belongs to.')) - parser.add_argument( - '--driver', - metavar='', - required=True, - help=_('Driver used to control the node [REQUIRED].')) - parser.add_argument( - '--driver-info', - metavar='', - action='append', - help=_('Key/value pair used by the driver, such as out-of-band ' - 'management credentials. Can be specified multiple times.')) - parser.add_argument( - '--property', - dest='properties', - metavar='', - action='append', - help=_('Key/value pair describing the physical characteristics of ' - 'the node. This is exported to Nova and used by the ' - 'scheduler. Can be specified multiple times.')) - parser.add_argument( - '--extra', - metavar='', - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.")) - parser.add_argument( - '--uuid', - metavar='', - help=_("Unique UUID for the node.")) - parser.add_argument( - '--name', - metavar='', - help=_("Unique name for the node.")) - parser.add_argument( - '--boot-interface', - metavar='', - help=_('Boot interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.')) - parser.add_argument( - '--console-interface', - metavar='', - help=_('Console interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.')) - parser.add_argument( - '--deploy-interface', - metavar='', - help=_('Deploy interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.')) - parser.add_argument( - '--inspect-interface', - metavar='', - help=_('Inspect interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.')) - parser.add_argument( - '--management-interface', - metavar='', - help=_('Management interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.')) - parser.add_argument( - '--network-interface', - metavar='', - help=_('Network interface used for switching node to ' - 'cleaning/provisioning networks.')) - parser.add_argument( - '--power-interface', - metavar='', - help=_('Power interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.')) - parser.add_argument( - '--raid-interface', - metavar='', - help=_('RAID interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.')) - parser.add_argument( - '--storage-interface', - metavar='', - help=_('Storage interface used by the node\'s driver.')) - parser.add_argument( - '--vendor-interface', - metavar='', - help=_('Vendor interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.')) - parser.add_argument( - '--resource-class', - metavar='', - help=_('Resource class for mapping nodes to Nova flavors')) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - field_list = ['chassis_uuid', 'driver', 'driver_info', - 'properties', 'extra', 'uuid', 'name', - 'boot_interface', 'console_interface', - 'deploy_interface', 'inspect_interface', - 'management_interface', 'network_interface', - 'power_interface', 'raid_interface', - 'storage_interface', 'vendor_interface', - 'resource_class'] - fields = dict((k, v) for (k, v) in vars(parsed_args).items() - if k in field_list and not (v is None)) - fields = utils.args_array_to_dict(fields, 'driver_info') - fields = utils.args_array_to_dict(fields, 'extra') - fields = utils.args_array_to_dict(fields, 'properties') - node = baremetal_client.node.create(**fields)._info - - node.pop('links', None) - node.pop('ports', None) - node.pop('portgroups', None) - node.pop('states', None) - node.pop('volume', None) - - node.setdefault('chassis_uuid', '') - - return self.dict2columns(node) - - -class DeleteBaremetalNode(command.Command): - """Unregister baremetal node(s)""" - - log = logging.getLogger(__name__ + ".DeleteBaremetalNode") - - def get_parser(self, prog_name): - parser = super(DeleteBaremetalNode, self).get_parser(prog_name) - parser.add_argument( - "nodes", - metavar="", - nargs="+", - help=_("Node(s) to delete (name or UUID)")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - failures = [] - for node in parsed_args.nodes: - try: - baremetal_client.node.delete(node) - print(_('Deleted node %s') % node) - except exc.ClientException as e: - failures.append(_("Failed to delete node %(node)s: %(error)s") - % {'node': node, 'error': e}) - - if failures: - raise exc.ClientException("\n".join(failures)) - - -class DeleteBaremetal(DeleteBaremetalNode): - """Unregister a baremetal node. DEPRECATED""" - - # TODO(thrash): Remove after 11-July-2017 during the 'Queens' cycle. - log = logging.getLogger(__name__ + ".DeleteBaremetal") - - def take_action(self, parsed_args): - self.log.warning("This command is deprecated. Instead, use " - "'openstack baremetal node delete'.") - super(DeleteBaremetal, self).take_action(parsed_args) - - -class DeployBaremetalNode(ProvisionStateWithWait): - """Set provision state of baremetal node to 'deploy'""" - - log = logging.getLogger(__name__ + ".DeployBaremetalNode") - PROVISION_STATE = 'active' - - def get_parser(self, prog_name): - parser = super(DeployBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - '--config-drive', - metavar='', - default=None, - help=_("A gzipped, base64-encoded configuration drive string OR " - "the path to the configuration drive file OR the path to a " - "directory containing the config drive files. In case it's " - "a directory, a config drive will be generated from it. ")) - return parser - - -class InspectBaremetalNode(ProvisionStateWithWait): - """Set provision state of baremetal node to 'inspect'""" - - log = logging.getLogger(__name__ + ".InspectBaremetalNode") - PROVISION_STATE = 'inspect' - - -class ListBaremetalNode(command.Lister): - """List baremetal nodes""" - - log = logging.getLogger(__name__ + ".ListBaremetalNode") - - PROVISION_STATES = ['active', 'deleted', 'rebuild', 'inspect', 'provide', - 'manage', 'clean', 'adopt', 'abort'] - - def get_parser(self, prog_name): - parser = super(ListBaremetalNode, self).get_parser(prog_name) - parser.add_argument( - '--limit', - metavar='', - type=int, - help=_('Maximum number of nodes to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Baremetal API Service.') - ) - parser.add_argument( - '--marker', - metavar='', - help=_('Node UUID (for example, of the last node in the list from ' - 'a previous request). Returns the list of nodes after this ' - 'UUID.') - ) - parser.add_argument( - '--sort', - metavar="[:]", - help=_('Sort output by specified node fields and directions ' - '(asc or desc) (default: asc). Multiple fields and ' - 'directions can be specified, separated by comma.'), - ) - maint_group = parser.add_mutually_exclusive_group(required=False) - maint_group.add_argument( - '--maintenance', - dest='maintenance', - action='store_true', - default=None, - help=_("Limit list to nodes in maintenance mode"), - ) - maint_group.add_argument( - '--no-maintenance', - dest='maintenance', - action='store_false', - default=None, - help=_("Limit list to nodes not in maintenance mode"), - ) - associated_group = parser.add_mutually_exclusive_group() - associated_group.add_argument( - '--associated', - action='store_true', - help=_("List only nodes associated with an instance."), - ) - associated_group.add_argument( - '--unassociated', - action='store_true', - help=_('List only nodes not associated with an instance.'), - ) - parser.add_argument( - '--provision-state', - dest='provision_state', - metavar='', - help=_("List nodes in specified provision state.")) - parser.add_argument( - '--driver', - dest='driver', - metavar='', - help=_("Limit list to nodes with driver ")) - parser.add_argument( - '--resource-class', - dest='resource_class', - metavar='', - help=_("Limit list to nodes with resource class ")) - parser.add_argument( - '--chassis', - dest='chassis', - metavar='', - help=_("Limit list to nodes of this chassis")) - display_group = parser.add_mutually_exclusive_group(required=False) - display_group.add_argument( - '--long', - default=False, - help=_("Show detailed information about the nodes."), - action='store_true') - display_group.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - choices=res_fields.NODE_DETAILED_RESOURCE.fields, - help=_("One or more node fields. Only these fields will be " - "fetched from the server. Can not be used when '--long' " - "is specified.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - client = self.app.client_manager.baremetal - - columns = res_fields.NODE_RESOURCE.fields - labels = res_fields.NODE_RESOURCE.labels - - params = {} - if parsed_args.limit is not None and parsed_args.limit < 0: - raise exc.CommandError( - _('Expected non-negative --limit, got %s') % - parsed_args.limit) - params['limit'] = parsed_args.limit - params['marker'] = parsed_args.marker - if parsed_args.associated: - params['associated'] = True - if parsed_args.unassociated: - params['associated'] = False - if parsed_args.maintenance is not None: - params['maintenance'] = parsed_args.maintenance - if parsed_args.provision_state: - params['provision_state'] = parsed_args.provision_state - if parsed_args.driver: - params['driver'] = parsed_args.driver - if parsed_args.resource_class: - params['resource_class'] = parsed_args.resource_class - if parsed_args.chassis: - params['chassis'] = parsed_args.chassis - if parsed_args.long: - params['detail'] = parsed_args.long - columns = res_fields.NODE_DETAILED_RESOURCE.fields - labels = res_fields.NODE_DETAILED_RESOURCE.labels - elif parsed_args.fields: - params['detail'] = False - fields = itertools.chain.from_iterable(parsed_args.fields) - resource = res_fields.Resource(list(fields)) - columns = resource.fields - labels = resource.labels - params['fields'] = columns - - self.log.debug("params(%s)", params) - data = client.node.list(**params) - - data = oscutils.sort_items(data, parsed_args.sort) - - return (labels, - (oscutils.get_item_properties(s, columns, formatters={ - 'Properties': oscutils.format_dict},) for s in data)) - - -class ListBaremetal(ListBaremetalNode): - """List baremetal nodes. DEPRECATED""" - - # TODO(thrash): Remove after 11-July-2017 during the 'Queens' cycle. - log = logging.getLogger(__name__ + ".ListBaremetal") - - def take_action(self, parsed_args): - self.log.warning("This command is deprecated. Instead, use " - "'openstack baremetal node list'.") - return super(ListBaremetal, self).take_action(parsed_args) - - -class MaintenanceSetBaremetalNode(command.Command): - """Set baremetal node to maintenance mode""" - - log = logging.getLogger(__name__ + ".MaintenanceSetBaremetalNode") - - def get_parser(self, prog_name): - parser = super(MaintenanceSetBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node.") - ) - parser.add_argument( - '--reason', - metavar='', - default=None, - help=_("Reason for setting maintenance mode.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - baremetal_client.node.set_maintenance( - parsed_args.node, - True, - maint_reason=parsed_args.reason) - - -class MaintenanceUnsetBaremetalNode(command.Command): - """Unset baremetal node from maintenance mode""" - - log = logging.getLogger(__name__ + ".MaintenanceUnsetBaremetalNode") - - def get_parser(self, prog_name): - parser = super(MaintenanceUnsetBaremetalNode, - self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node.") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - baremetal_client.node.set_maintenance( - parsed_args.node, - False) - - -class ManageBaremetalNode(ProvisionStateWithWait): - """Set provision state of baremetal node to 'manage'""" - - log = logging.getLogger(__name__ + ".ManageBaremetalNode") - PROVISION_STATE = 'manage' - - -class PassthruCallBaremetalNode(command.Command): - """Call a vendor passthu method for a node""" - - log = logging.getLogger(__name__ + ".PassthuCallBaremetalNode") - - def get_parser(self, prog_name): - parser = super(PassthruCallBaremetalNode, self).get_parser( - prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - parser.add_argument( - 'method', - metavar='', - help=_("Vendor passthru method to be executed") - ) - parser.add_argument( - '--arg', - metavar='', - action='append', - help=_("Argument to pass to the passthru method (repeat option " - "to specify multiple arguments)") - ) - parser.add_argument( - '--http-method', - metavar='', - choices=v1_utils.HTTP_METHODS, - default='POST', - help=(_("The HTTP method to use in the passthru request. One of " - "%s. Defaults to POST.") % - oscutils.format_list(v1_utils.HTTP_METHODS)) - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - arguments = utils.key_value_pairs_to_dict(parsed_args.arg) - resp = baremetal_client.node.vendor_passthru( - parsed_args.node, - parsed_args.method, - http_method=parsed_args.http_method, - args=arguments) - if resp: - # Print the raw response; we don't know how it should be formatted - print(str(resp.to_dict())) - - -class PassthruListBaremetalNode(command.Lister): - """List vendor passthru methods for a node""" - - log = logging.getLogger(__name__ + ".PassthruListBaremetalNode") - - def get_parser(self, prog_name): - parser = super(PassthruListBaremetalNode, self).get_parser( - prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - methods = baremetal_client.node.get_vendor_passthru_methods( - parsed_args.node) - data = [] - for method, response in methods.items(): - response['name'] = method - response['http_methods'] = oscutils.format_list( - response['http_methods']) - data.append(response) - - return ( - res_fields.VENDOR_PASSTHRU_METHOD_RESOURCE.labels, - (oscutils.get_dict_properties( - s, res_fields.VENDOR_PASSTHRU_METHOD_RESOURCE.fields) - for s in data)) - - -class PowerBaremetalNode(command.Command): - """Set power state of baremetal node""" - - log = logging.getLogger(__name__ + ".PowerBaremetalNode") - - def get_parser(self, prog_name): - parser = super(PowerBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'power_state', - metavar='', - choices=['on', 'off'], - help=_("Power node on or off") - ) - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node.") - ) - parser.add_argument( - '--soft', - dest='soft', - action='store_true', - default=False, - help=_("Request graceful power-off.") - ) - parser.add_argument( - '--power-timeout', - metavar='', - default=None, - type=int, - help=_("Timeout (in seconds, positive integer) to wait for the " - "target power state before erroring out.") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - baremetal_client.node.set_power_state( - parsed_args.node, parsed_args.power_state, parsed_args.soft, - timeout=parsed_args.power_timeout) - - -class ProvideBaremetalNode(ProvisionStateWithWait): - """Set provision state of baremetal node to 'provide'""" - - log = logging.getLogger(__name__ + ".ProvideBaremetalNode") - PROVISION_STATE = 'provide' - - -class RebootBaremetalNode(command.Command): - """Reboot baremetal node""" - - log = logging.getLogger(__name__ + ".RebootBaremetalNode") - - def get_parser(self, prog_name): - parser = super(RebootBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node.") - ) - parser.add_argument( - '--soft', - dest='soft', - action='store_true', - default=False, - help=_("Request Graceful reboot.") - ) - parser.add_argument( - '--power-timeout', - metavar='', - default=None, - type=int, - help=_("Timeout (in seconds, positive integer) to wait for the " - "target power state before erroring out.") - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - baremetal_client.node.set_power_state( - parsed_args.node, 'reboot', parsed_args.soft, - timeout=parsed_args.power_timeout) - - -class RebuildBaremetalNode(ProvisionStateWithWait): - """Set provision state of baremetal node to 'rebuild'""" - - log = logging.getLogger(__name__ + ".RebuildBaremetalNode") - PROVISION_STATE = 'rebuild' - - -class SetBaremetalNode(command.Command): - """Set baremetal properties""" - - log = logging.getLogger(__name__ + ".SetBaremetalNode") - - def get_parser(self, prog_name): - parser = super(SetBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node."), - ) - parser.add_argument( - "--instance-uuid", - metavar="", - help=_("Set instance UUID of node to "), - ) - parser.add_argument( - "--name", - metavar="", - help=_("Set the name of the node"), - ) - parser.add_argument( - "--chassis-uuid", - metavar="", - help=_("Set the chassis for the node"), - ) - parser.add_argument( - "--driver", - metavar="", - help=_("Set the driver for the node"), - ) - parser.add_argument( - '--boot-interface', - metavar='', - help=_('Set the boot interface for the node'), - ) - parser.add_argument( - '--console-interface', - metavar='', - help=_('Set the console interface for the node'), - ) - parser.add_argument( - '--deploy-interface', - metavar='', - help=_('Set the deploy interface for the node'), - ) - parser.add_argument( - '--inspect-interface', - metavar='', - help=_('Set the inspect interface for the node'), - ) - parser.add_argument( - '--management-interface', - metavar='', - help=_('Set the management interface for the node'), - ) - parser.add_argument( - '--network-interface', - metavar='', - help=_('Set the network interface for the node'), - ) - parser.add_argument( - '--power-interface', - metavar='', - help=_('Set the power interface for the node'), - ) - parser.add_argument( - '--raid-interface', - metavar='', - help=_('Set the RAID interface for the node'), - ) - parser.add_argument( - '--storage-interface', - metavar='', - help=_('Set the storage interface for the node'), - ) - parser.add_argument( - '--vendor-interface', - metavar='', - help=_('Set the vendor interface for the node'), - ) - parser.add_argument( - '--resource-class', - metavar='', - help=_('Set the resource class for the node'), - ) - parser.add_argument( - '--target-raid-config', - metavar='', - help=_('Set the target RAID configuration (JSON) for the node. ' - 'This can be one of: 1. a file containing JSON data of the ' - 'RAID configuration; 2. "-" to read the contents from ' - 'standard input; or 3. a valid JSON string.'), - ) - parser.add_argument( - "--property", - metavar="", - action='append', - help=_('Property to set on this baremetal node ' - '(repeat option to set multiple properties)'), - ) - parser.add_argument( - "--extra", - metavar="", - action='append', - help=_('Extra to set on this baremetal node ' - '(repeat option to set multiple extras)'), - ) - parser.add_argument( - "--driver-info", - metavar="", - action='append', - help=_('Driver information to set on this baremetal node ' - '(repeat option to set multiple driver infos)'), - ) - parser.add_argument( - "--instance-info", - metavar="", - action='append', - help=_('Instance information to set on this baremetal node ' - '(repeat option to set multiple instance infos)'), - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - # NOTE(rloo): Do this before updating the rest. Otherwise, it won't - # work if parsed_args.node is the name and the name is - # also being modified. - if parsed_args.target_raid_config: - raid_config = parsed_args.target_raid_config - if raid_config == '-': - raid_config = utils.get_from_stdin('target_raid_config') - raid_config = utils.handle_json_or_file_arg(raid_config) - baremetal_client.node.set_target_raid_config(parsed_args.node, - raid_config) - - properties = [] - if parsed_args.instance_uuid: - instance_uuid = ["instance_uuid=%s" % parsed_args.instance_uuid] - properties.extend(utils.args_array_to_patch( - 'add', instance_uuid)) - if parsed_args.name: - name = ["name=%s" % parsed_args.name] - properties.extend(utils.args_array_to_patch( - 'add', name)) - if parsed_args.chassis_uuid: - chassis_uuid = ["chassis_uuid=%s" % parsed_args.chassis_uuid] - properties.extend(utils.args_array_to_patch( - 'add', chassis_uuid)) - if parsed_args.driver: - driver = ["driver=%s" % parsed_args.driver] - properties.extend(utils.args_array_to_patch( - 'add', driver)) - if parsed_args.boot_interface: - boot_interface = [ - "boot_interface=%s" % parsed_args.boot_interface] - properties.extend(utils.args_array_to_patch( - 'add', boot_interface)) - if parsed_args.console_interface: - console_interface = [ - "console_interface=%s" % parsed_args.console_interface] - properties.extend(utils.args_array_to_patch( - 'add', console_interface)) - if parsed_args.deploy_interface: - deploy_interface = [ - "deploy_interface=%s" % parsed_args.deploy_interface] - properties.extend(utils.args_array_to_patch( - 'add', deploy_interface)) - if parsed_args.inspect_interface: - inspect_interface = [ - "inspect_interface=%s" % parsed_args.inspect_interface] - properties.extend(utils.args_array_to_patch( - 'add', inspect_interface)) - if parsed_args.management_interface: - management_interface = [ - "management_interface=%s" % parsed_args.management_interface] - properties.extend(utils.args_array_to_patch( - 'add', management_interface)) - if parsed_args.network_interface: - network_interface = [ - "network_interface=%s" % parsed_args.network_interface] - properties.extend(utils.args_array_to_patch( - 'add', network_interface)) - if parsed_args.power_interface: - power_interface = [ - "power_interface=%s" % parsed_args.power_interface] - properties.extend(utils.args_array_to_patch( - 'add', power_interface)) - if parsed_args.raid_interface: - raid_interface = [ - "raid_interface=%s" % parsed_args.raid_interface] - properties.extend(utils.args_array_to_patch( - 'add', raid_interface)) - if parsed_args.storage_interface: - storage_interface = [ - "storage_interface=%s" % parsed_args.storage_interface] - properties.extend(utils.args_array_to_patch( - 'add', storage_interface)) - if parsed_args.vendor_interface: - vendor_interface = [ - "vendor_interface=%s" % parsed_args.vendor_interface] - properties.extend(utils.args_array_to_patch( - 'add', vendor_interface)) - if parsed_args.resource_class: - resource_class = [ - "resource_class=%s" % parsed_args.resource_class] - properties.extend(utils.args_array_to_patch( - 'add', resource_class)) - if parsed_args.property: - properties.extend(utils.args_array_to_patch( - 'add', ['properties/' + x for x in parsed_args.property])) - if parsed_args.extra: - properties.extend(utils.args_array_to_patch( - 'add', ['extra/' + x for x in parsed_args.extra])) - if parsed_args.driver_info: - properties.extend(utils.args_array_to_patch( - 'add', ['driver_info/' + x for x in parsed_args.driver_info])) - if parsed_args.instance_info: - properties.extend(utils.args_array_to_patch( - 'add', ['instance_info/' + x for x - in parsed_args.instance_info])) - if properties: - baremetal_client.node.update(parsed_args.node, properties) - else: - self.log.warning("Please specify what to set.") - - -class SetBaremetal(SetBaremetalNode): - """Set baremetal properties. DEPRECATED""" - - # TODO(thrash): Remove after 11-July-2017 during the 'Queens' cycle. - log = logging.getLogger(__name__ + ".SetBaremetal") - - def take_action(self, parsed_args): - self.log.warning("This command is deprecated. Instead, use " - "'openstack baremetal node set'.") - return super(SetBaremetal, self).take_action(parsed_args) - - -class ShowBaremetalNode(command.ShowOne): - """Show baremetal node details""" - - log = logging.getLogger(__name__ + ".ShowBaremetalNode") - - def get_parser(self, prog_name): - parser = super(ShowBaremetalNode, self).get_parser(prog_name) - parser.add_argument( - "node", - metavar="", - help=_("Name or UUID of the node (or instance UUID if --instance " - "is specified)")) - parser.add_argument( - '--instance', - dest='instance_uuid', - action='store_true', - default=False, - help=_(' is an instance UUID.')) - parser.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - choices=res_fields.NODE_DETAILED_RESOURCE.fields, - default=[], - help=_("One or more node fields. Only these fields will be " - "fetched from the server.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - fields = list(itertools.chain.from_iterable(parsed_args.fields)) - fields = fields if fields else None - if parsed_args.instance_uuid: - node = baremetal_client.node.get_by_instance_uuid( - parsed_args.node, fields=fields)._info - else: - node = baremetal_client.node.get( - parsed_args.node, fields=fields)._info - node.pop("links", None) - node.pop("ports", None) - node.pop('portgroups', None) - node.pop('states', None) - node.pop('volume', None) - - if not fields or 'chassis_uuid' in fields: - node.setdefault('chassis_uuid', '') - - return self.dict2columns(node) - - -class ShowBaremetal(ShowBaremetalNode): - """Show baremetal node details. DEPRECATED""" - - # TODO(thrash): Remove after 11-July-2017 during the 'Queens' cycle. - log = logging.getLogger(__name__ + ".ShowBaremetal") - - def take_action(self, parsed_args): - self.log.warning("This command is deprecated. Instead, use " - "'openstack baremetal node show'.") - return super(ShowBaremetal, self).take_action(parsed_args) - - -class UndeployBaremetalNode(ProvisionStateWithWait): - """Set provision state of baremetal node to 'deleted'""" - - log = logging.getLogger(__name__ + ".UndeployBaremetalNode") - PROVISION_STATE = 'deleted' - - -class UnsetBaremetalNode(command.Command): - """Unset baremetal properties""" - log = logging.getLogger(__name__ + ".UnsetBaremetalNode") - - def get_parser(self, prog_name): - parser = super(UnsetBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node.") - ) - parser.add_argument( - '--instance-uuid', - action='store_true', - default=False, - help=_('Unset instance UUID on this baremetal node') - ) - parser.add_argument( - "--name", - action='store_true', - help=_("Unset the name of the node"), - ) - parser.add_argument( - "--resource-class", - dest='resource_class', - action='store_true', - help=_("Unset the resource class of the node"), - ) - parser.add_argument( - "--target-raid-config", - action='store_true', - help=_("Unset the target RAID configuration of the node"), - ) - parser.add_argument( - '--property', - metavar='', - action='append', - help=_('Property to unset on this baremetal node ' - '(repeat option to unset multiple properties)'), - ) - parser.add_argument( - "--extra", - metavar="", - action='append', - help=_('Extra to unset on this baremetal node ' - '(repeat option to unset multiple extras)'), - ) - parser.add_argument( - "--driver-info", - metavar="", - action='append', - help=_('Driver information to unset on this baremetal node ' - '(repeat option to unset multiple driver informations)'), - ) - parser.add_argument( - "--instance-info", - metavar="", - action='append', - help=_('Instance information to unset on this baremetal node ' - '(repeat option to unset multiple instance informations)'), - ) - parser.add_argument( - "--chassis-uuid", - dest='chassis_uuid', - action='store_true', - help=_('Unset chassis UUID on this baremetal node'), - ) - parser.add_argument( - "--boot-interface", - dest='boot_interface', - action='store_true', - help=_('Unset boot interface on this baremetal node'), - ) - parser.add_argument( - "--console-interface", - dest='console_interface', - action='store_true', - help=_('Unset console interface on this baremetal node'), - ) - parser.add_argument( - "--deploy-interface", - dest='deploy_interface', - action='store_true', - help=_('Unset deploy interface on this baremetal node'), - ) - parser.add_argument( - "--inspect-interface", - dest='inspect_interface', - action='store_true', - help=_('Unset inspect interface on this baremetal node'), - ) - parser.add_argument( - "--management-interface", - dest='management_interface', - action='store_true', - help=_('Unset management interface on this baremetal node'), - ) - parser.add_argument( - "--network-interface", - dest='network_interface', - action='store_true', - help=_('Unset network interface on this baremetal node'), - ) - parser.add_argument( - "--power-interface", - dest='power_interface', - action='store_true', - help=_('Unset power interface on this baremetal node'), - ) - parser.add_argument( - "--raid-interface", - dest='raid_interface', - action='store_true', - help=_('Unset RAID interface on this baremetal node'), - ) - parser.add_argument( - "--storage-interface", - dest='storage_interface', - action='store_true', - help=_('Unset storage interface on this baremetal node'), - ) - parser.add_argument( - "--vendor-interface", - dest='vendor_interface', - action='store_true', - help=_('Unset vendor interface on this baremetal node'), - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - # NOTE(rloo): Do this before removing the rest. Otherwise, it won't - # work if parsed_args.node is the name and the name is - # also being removed. - if parsed_args.target_raid_config: - baremetal_client.node.set_target_raid_config(parsed_args.node, {}) - - properties = [] - if parsed_args.instance_uuid: - properties.extend(utils.args_array_to_patch('remove', - ['instance_uuid'])) - if parsed_args.name: - properties.extend(utils.args_array_to_patch('remove', - ['name'])) - if parsed_args.resource_class: - properties.extend(utils.args_array_to_patch('remove', - ['resource_class'])) - if parsed_args.property: - properties.extend(utils.args_array_to_patch('remove', - ['properties/' + x - for x in parsed_args.property])) - if parsed_args.extra: - properties.extend(utils.args_array_to_patch('remove', - ['extra/' + x for x in parsed_args.extra])) - if parsed_args.driver_info: - properties.extend(utils.args_array_to_patch('remove', - ['driver_info/' + x for x - in parsed_args.driver_info])) - if parsed_args.instance_info: - properties.extend(utils.args_array_to_patch('remove', - ['instance_info/' + x for x - in parsed_args.instance_info])) - if parsed_args.chassis_uuid: - properties.extend(utils.args_array_to_patch('remove', - ['chassis_uuid'])) - if parsed_args.boot_interface: - properties.extend(utils.args_array_to_patch('remove', - ['boot_interface'])) - if parsed_args.console_interface: - properties.extend(utils.args_array_to_patch('remove', - ['console_interface'])) - if parsed_args.deploy_interface: - properties.extend(utils.args_array_to_patch('remove', - ['deploy_interface'])) - if parsed_args.inspect_interface: - properties.extend(utils.args_array_to_patch('remove', - ['inspect_interface'])) - if parsed_args.management_interface: - properties.extend(utils.args_array_to_patch('remove', - ['management_interface'])) - if parsed_args.network_interface: - properties.extend(utils.args_array_to_patch('remove', - ['network_interface'])) - if parsed_args.power_interface: - properties.extend(utils.args_array_to_patch('remove', - ['power_interface'])) - if parsed_args.raid_interface: - properties.extend(utils.args_array_to_patch('remove', - ['raid_interface'])) - if parsed_args.storage_interface: - properties.extend(utils.args_array_to_patch('remove', - ['storage_interface'])) - if parsed_args.vendor_interface: - properties.extend(utils.args_array_to_patch('remove', - ['vendor_interface'])) - if properties: - baremetal_client.node.update(parsed_args.node, properties) - else: - self.log.warning("Please specify what to unset.") - - -class UnsetBaremetal(UnsetBaremetalNode): - """Unset baremetal properties. DEPRECATED""" - - # TODO(thrash): Remove after 11-July-2017 during the 'Queens' cycle. - log = logging.getLogger(__name__ + ".UnsetBaremetal") - - def take_action(self, parsed_args): - self.log.warning("This command is deprecated. Instead, use " - "'openstack baremetal node unset'.") - super(UnsetBaremetal, self).take_action(parsed_args) - - -class ValidateBaremetalNode(command.Lister): - """Validate a node's driver interfaces""" - - log = logging.getLogger(__name__ + ".ValidateBaremetalNode") - - def get_parser(self, prog_name): - parser = super(ValidateBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - interfaces = baremetal_client.node.validate(parsed_args.node)._info - data = [] - for key, value in interfaces.items(): - interface = {'interface': key} - interface.update(value) - data.append(interface) - field_labels = ['Interface', 'Result', 'Reason'] - fields = ['interface', 'result', 'reason'] - data = oscutils.sort_items(data, 'interface') - return (field_labels, - (oscutils.get_dict_properties(s, fields) for s in data)) - - -class VifListBaremetalNode(command.Lister): - """Show attached VIFs for a node""" - - log = logging.getLogger(__name__ + ".VifListBaremetalNode") - - def get_parser(self, prog_name): - parser = super(VifListBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - columns = res_fields.VIF_RESOURCE.fields - labels = res_fields.VIF_RESOURCE.labels - - baremetal_client = self.app.client_manager.baremetal - data = baremetal_client.node.vif_list(parsed_args.node) - - return (labels, - (oscutils.get_item_properties(s, columns) for s in data)) - - -class VifAttachBaremetalNode(command.Command): - """Attach VIF to a given node""" - - log = logging.getLogger(__name__ + ".VifAttachBaremetalNode") - - def get_parser(self, prog_name): - parser = super(VifAttachBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - parser.add_argument( - 'vif_id', - metavar='', - help=_("Name or UUID of the VIF to attach to a node.") - ) - parser.add_argument( - '--vif-info', - metavar='', - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times. The mandatory 'id' " - "parameter cannot be specified as a key.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - fields = utils.key_value_pairs_to_dict(parsed_args.vif_info or []) - baremetal_client.node.vif_attach(parsed_args.node, parsed_args.vif_id, - **fields) - - -class VifDetachBaremetalNode(command.Command): - """Detach VIF from a given node""" - - log = logging.getLogger(__name__ + ".VifDetachBaremetalNode") - - def get_parser(self, prog_name): - parser = super(VifDetachBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node") - ) - parser.add_argument( - 'vif_id', - metavar='', - help=_("Name or UUID of the VIF to detach from a node.") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - baremetal_client.node.vif_detach(parsed_args.node, parsed_args.vif_id) - - -class InjectNmiBaremetalNode(command.Command): - """Inject NMI to baremetal node""" - - log = logging.getLogger(__name__ + ".InjectNmiBaremetalNode") - - def get_parser(self, prog_name): - parser = super(InjectNmiBaremetalNode, self).get_parser(prog_name) - - parser.add_argument( - 'node', - metavar='', - help=_("Name or UUID of the node.") - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - baremetal_client.node.inject_nmi(parsed_args.node) diff --git a/ironicclient/osc/v1/baremetal_port.py b/ironicclient/osc/v1/baremetal_port.py deleted file mode 100644 index 3e934fe..0000000 --- a/ironicclient/osc/v1/baremetal_port.py +++ /dev/null @@ -1,496 +0,0 @@ -# -# Copyright 2015 Red Hat, Inc. -# -# 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 itertools -import logging - -from osc_lib.command import command -from osc_lib import utils as oscutils - -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.v1 import resource_fields as res_fields - - -class CreateBaremetalPort(command.ShowOne): - """Create a new port""" - - log = logging.getLogger(__name__ + ".CreateBaremetalPort") - - def get_parser(self, prog_name): - parser = super(CreateBaremetalPort, self).get_parser(prog_name) - - parser.add_argument( - 'address', - metavar='
', - help=_('MAC address for this port.') - ) - parser.add_argument( - '--node', - dest='node_uuid', - metavar='', - required=True, - help=_('UUID of the node that this port belongs to.') - ) - parser.add_argument( - '--uuid', - dest='uuid', - metavar='', - help=_('UUID of the port.')) - parser.add_argument( - '--extra', - metavar="", - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.") - ) - parser.add_argument( - '--local-link-connection', - metavar="", - action='append', - help=_("Key/value metadata describing Local link connection " - "information. Valid keys are 'switch_info', 'switch_id', " - "and 'port_id'. The keys 'switch_id' and 'port_id' are " - "required. Can be specified multiple times.") - ) - parser.add_argument( - '-l', - dest='local_link_connection_deprecated', - metavar="", - action='append', - help=_("DEPRECATED. Please use --local-link-connection instead. " - "Key/value metadata describing Local link connection " - "information. Valid keys are 'switch_info', 'switch_id', " - "and 'port_id'. The keys 'switch_id' and 'port_id' are " - "required. Can be specified multiple times.") - ) - parser.add_argument( - '--pxe-enabled', - metavar='', - help=_('Indicates whether this Port should be used when ' - 'PXE booting this Node.') - ) - - parser.add_argument( - '--port-group', - dest='portgroup_uuid', - metavar='', - help=_("UUID of the port group that this port belongs to.")) - - parser.add_argument( - '--physical-network', - dest='physical_network', - metavar='', - help=_("Name of the physical network to which this port is " - "connected.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - baremetal_client = self.app.client_manager.baremetal - - if parsed_args.local_link_connection_deprecated: - self.log.warning("Please use --local-link-connection instead " - "of -l, as it is deprecated and will be " - "removed in future releases.") - # It is parsed to either None, or to an array - if parsed_args.local_link_connection: - parsed_args.local_link_connection.extend( - parsed_args.local_link_connection_deprecated) - else: - parsed_args.local_link_connection = ( - parsed_args.local_link_connection_deprecated) - - field_list = ['address', 'uuid', 'extra', 'node_uuid', 'pxe_enabled', - 'local_link_connection', 'portgroup_uuid', - 'physical_network'] - fields = dict((k, v) for (k, v) in vars(parsed_args).items() - if k in field_list and v is not None) - fields = utils.args_array_to_dict(fields, 'extra') - fields = utils.args_array_to_dict(fields, 'local_link_connection') - port = baremetal_client.port.create(**fields) - - data = dict([(f, getattr(port, f, '')) for f in - res_fields.PORT_DETAILED_RESOURCE.fields]) - - return self.dict2columns(data) - - -class ShowBaremetalPort(command.ShowOne): - """Show baremetal port details.""" - - log = logging.getLogger(__name__ + ".ShowBaremetalPort") - - def get_parser(self, prog_name): - parser = super(ShowBaremetalPort, self).get_parser(prog_name) - parser.add_argument( - "port", - metavar="", - help=_("UUID of the port (or MAC address if --address is " - "specified).") - ) - parser.add_argument( - '--address', - dest='address', - action='store_true', - default=False, - help=_(' is the MAC address (instead of the UUID) of the ' - 'port.') - ) - parser.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - choices=res_fields.PORT_DETAILED_RESOURCE.fields, - default=[], - help=_("One or more port fields. Only these fields will be " - "fetched from the server.") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - fields = list(itertools.chain.from_iterable(parsed_args.fields)) - fields = fields if fields else None - - if parsed_args.address: - port = baremetal_client.port.get_by_address( - parsed_args.port, fields=fields)._info - else: - port = baremetal_client.port.get( - parsed_args.port, fields=fields)._info - - port.pop("links", None) - return zip(*sorted(port.items())) - - -class UnsetBaremetalPort(command.Command): - """Unset baremetal port properties.""" - log = logging.getLogger(__name__ + ".UnsetBaremetalPort") - - def get_parser(self, prog_name): - parser = super(UnsetBaremetalPort, self).get_parser(prog_name) - - parser.add_argument( - 'port', - metavar='', - help=_("UUID of the port.") - ) - parser.add_argument( - "--extra", - metavar="", - action='append', - help=_('Extra to unset on this baremetal port ' - '(repeat option to unset multiple extras)') - ) - - parser.add_argument( - '--port-group', - action='store_true', - dest='portgroup', - help=_("Remove port from the port group")) - - parser.add_argument( - '--physical-network', - action='store_true', - dest='physical_network', - help=_("Unset the physical network on this baremetal port.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - properties = [] - if parsed_args.extra: - properties.extend(utils.args_array_to_patch( - 'remove', - ['extra/' + x for x in parsed_args.extra])) - if parsed_args.portgroup: - properties.extend(utils.args_array_to_patch('remove', - ['portgroup_uuid'])) - if parsed_args.physical_network: - properties.extend(utils.args_array_to_patch('remove', - ['physical_network'])) - - if properties: - baremetal_client.port.update(parsed_args.port, properties) - else: - self.log.warning("Please specify what to unset.") - - -class SetBaremetalPort(command.Command): - """Set baremetal port properties.""" - - log = logging.getLogger(__name__ + ".SetBaremetalPort") - - def get_parser(self, prog_name): - parser = super(SetBaremetalPort, self).get_parser(prog_name) - - parser.add_argument( - 'port', - metavar='', - help=_("UUID of the port") - ) - parser.add_argument( - '--node', - dest='node_uuid', - metavar='', - help=_('Set UUID of the node that this port belongs to') - ) - parser.add_argument( - "--address", - metavar="
", - dest='address', - help=_("Set MAC address for this port") - ) - parser.add_argument( - "--extra", - metavar="", - action='append', - help=_('Extra to set on this baremetal port ' - '(repeat option to set multiple extras)') - ) - parser.add_argument( - "--port-group", - metavar="", - dest='portgroup_uuid', - help=_('Set UUID of the port group that this port belongs to.')) - parser.add_argument( - "--local-link-connection", - metavar="", - action='append', - help=_("Key/value metadata describing local link connection " - "information. Valid keys are 'switch_info', 'switch_id', " - "and 'port_id'. The keys 'switch_id' and 'port_id' are " - "required. Can be specified multiple times.") - ) - pxe_enabled_group = parser.add_mutually_exclusive_group(required=False) - pxe_enabled_group.add_argument( - "--pxe-enabled", - dest='pxe_enabled', - default=None, - action='store_true', - help=_("Indicates that this port should be used when " - "PXE booting this node (default)") - ) - pxe_enabled_group.add_argument( - "--pxe-disabled", - dest='pxe_enabled', - default=None, - action='store_false', - help=_("Indicates that this port should not be used when " - "PXE booting this node") - ) - parser.add_argument( - '--physical-network', - metavar='', - dest='physical_network', - help=_("Set the name of the physical network to which this port " - "is connected.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - properties = [] - if parsed_args.node_uuid: - node_uuid = ["node_uuid=%s" % parsed_args.node_uuid] - properties.extend(utils.args_array_to_patch( - 'add', node_uuid)) - if parsed_args.address: - address = ["address=%s" % parsed_args.address] - properties.extend(utils.args_array_to_patch('add', address)) - if parsed_args.extra: - properties.extend(utils.args_array_to_patch( - 'add', ['extra/' + x for x in parsed_args.extra])) - if parsed_args.portgroup_uuid: - portgroup_uuid = ["portgroup_uuid=%s" % parsed_args.portgroup_uuid] - properties.extend(utils.args_array_to_patch('add', portgroup_uuid)) - if parsed_args.local_link_connection: - properties.extend(utils.args_array_to_patch( - 'add', ['local_link_connection/' + x for x in - parsed_args.local_link_connection])) - if parsed_args.pxe_enabled is not None: - properties.extend(utils.args_array_to_patch( - 'add', ['pxe_enabled=%s' % parsed_args.pxe_enabled])) - if parsed_args.physical_network: - physical_network = ["physical_network=%s" % - parsed_args.physical_network] - properties.extend(utils.args_array_to_patch('add', - physical_network)) - - if properties: - baremetal_client.port.update(parsed_args.port, properties) - else: - self.log.warning("Please specify what to set.") - - -class DeleteBaremetalPort(command.Command): - """Delete port(s).""" - - log = logging.getLogger(__name__ + ".DeleteBaremetalPort") - - def get_parser(self, prog_name): - parser = super(DeleteBaremetalPort, self).get_parser(prog_name) - parser.add_argument( - "ports", - metavar="", - nargs="+", - help=_("UUID(s) of the port(s) to delete.") - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - failures = [] - for port in parsed_args.ports: - try: - baremetal_client.port.delete(port) - print(_('Deleted port %s') % port) - except exc.ClientException as e: - failures.append(_("Failed to delete port %(port)s: %(error)s") - % {'port': port, 'error': e}) - - if failures: - raise exc.ClientException("\n".join(failures)) - - -class ListBaremetalPort(command.Lister): - """List baremetal ports.""" - - log = logging.getLogger(__name__ + ".ListBaremetalPort") - - def get_parser(self, prog_name): - parser = super(ListBaremetalPort, self).get_parser(prog_name) - parser.add_argument( - '--address', - dest='address', - metavar='', - help=_("Only show information for the port with this MAC address.") - ) - parser.add_argument( - '--node', - dest='node', - metavar='', - help=_("Only list ports of this node (name or UUID).") - ) - parser.add_argument( - "--port-group", - metavar="", - dest='portgroup', - help=_('Only list ports of this port group (name or UUID).')) - parser.add_argument( - '--limit', - metavar='', - type=int, - help=_('Maximum number of ports to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Ironic API Service.') - ) - parser.add_argument( - '--marker', - metavar='', - help=_('Port UUID (for example, of the last port in the list ' - 'from a previous request). Returns the list of ports ' - 'after this UUID.') - ) - parser.add_argument( - '--sort', - metavar="[:]", - help=_('Sort output by specified port fields and directions ' - '(asc or desc) (default: asc). Multiple fields and ' - 'directions can be specified, separated by comma.') - ) - display_group = parser.add_mutually_exclusive_group() - display_group.add_argument( - '--long', - dest='detail', - action='store_true', - default=False, - help=_("Show detailed information about ports.") - ) - display_group.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - choices=res_fields.PORT_DETAILED_RESOURCE.fields, - help=_("One or more port fields. Only these fields will be " - "fetched from the server. Can not be used when " - "'--long' is specified.") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - client = self.app.client_manager.baremetal - - columns = res_fields.PORT_RESOURCE.fields - labels = res_fields.PORT_RESOURCE.labels - - params = {} - if parsed_args.limit is not None and parsed_args.limit < 0: - raise exc.CommandError( - _('Expected non-negative --limit, got %s') % - parsed_args.limit) - params['limit'] = parsed_args.limit - params['marker'] = parsed_args.marker - - if parsed_args.address is not None: - params['address'] = parsed_args.address - if parsed_args.node is not None: - params['node'] = parsed_args.node - if parsed_args.portgroup is not None: - params['portgroup'] = parsed_args.portgroup - - if parsed_args.detail: - params['detail'] = parsed_args.detail - columns = res_fields.PORT_DETAILED_RESOURCE.fields - labels = res_fields.PORT_DETAILED_RESOURCE.labels - - elif parsed_args.fields: - params['detail'] = False - fields = itertools.chain.from_iterable(parsed_args.fields) - resource = res_fields.Resource(list(fields)) - columns = resource.fields - labels = resource.labels - params['fields'] = columns - - self.log.debug("params(%s)", params) - data = client.port.list(**params) - - data = oscutils.sort_items(data, parsed_args.sort) - - return (labels, - (oscutils.get_item_properties(s, columns, formatters={ - 'extra': oscutils.format_dict},) for s in data)) diff --git a/ironicclient/osc/v1/baremetal_portgroup.py b/ironicclient/osc/v1/baremetal_portgroup.py deleted file mode 100644 index 20c7625..0000000 --- a/ironicclient/osc/v1/baremetal_portgroup.py +++ /dev/null @@ -1,461 +0,0 @@ -# -# Copyright 2016 Mirantis, Inc. -# -# 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 itertools -import logging - -from osc_lib.command import command -from osc_lib import utils as oscutils - -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.v1 import resource_fields as res_fields - - -class CreateBaremetalPortGroup(command.ShowOne): - """Create a new baremetal port group.""" - - log = logging.getLogger(__name__ + ".CreateBaremetalPortGroup") - - def get_parser(self, prog_name): - parser = super(CreateBaremetalPortGroup, self).get_parser(prog_name) - - parser.add_argument( - '--node', - dest='node_uuid', - metavar='', - required=True, - help=_('UUID of the node that this port group belongs to.')) - parser.add_argument( - '--address', - metavar='', - help=_('MAC address for this port group.')) - parser.add_argument( - '--name', - dest='name', - help=_('Name of the port group.')) - parser.add_argument( - '--uuid', - dest='uuid', - help=_('UUID of the port group.')) - parser.add_argument( - '--extra', - metavar="", - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.")) - parser.add_argument( - '--mode', - help=_('Mode of the port group. For possible values, refer to ' - 'https://www.kernel.org/doc/Documentation/networking' - '/bonding.txt.')) - parser.add_argument( - '--property', - dest='properties', - metavar="", - action='append', - help=_("Key/value property related to this port group's " - "configuration. Can be specified multiple times.")) - standalone_ports_group = parser.add_mutually_exclusive_group() - standalone_ports_group.add_argument( - '--support-standalone-ports', - action='store_true', - help=_("Ports that are members of this port group " - "can be used as stand-alone ports. (default)")) - standalone_ports_group.add_argument( - '--unsupport-standalone-ports', - action='store_true', - help=_("Ports that are members of this port group " - "cannot be used as stand-alone ports.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - baremetal_client = self.app.client_manager.baremetal - - field_list = ['node_uuid', 'address', 'name', 'uuid', 'extra', 'mode', - 'properties'] - fields = dict((k, v) for (k, v) in vars(parsed_args).items() - if k in field_list and v is not None) - if parsed_args.support_standalone_ports: - fields['standalone_ports_supported'] = True - if parsed_args.unsupport_standalone_ports: - fields['standalone_ports_supported'] = False - - fields = utils.args_array_to_dict(fields, 'extra') - fields = utils.args_array_to_dict(fields, 'properties') - portgroup = baremetal_client.portgroup.create(**fields) - - data = dict([(f, getattr(portgroup, f, '')) for f in - res_fields.PORTGROUP_DETAILED_RESOURCE.fields]) - - return self.dict2columns(data) - - -class ShowBaremetalPortGroup(command.ShowOne): - """Show baremetal port group details.""" - - log = logging.getLogger(__name__ + ".ShowBaremetalPortGroup") - - def get_parser(self, prog_name): - parser = super(ShowBaremetalPortGroup, self).get_parser(prog_name) - parser.add_argument( - "portgroup", - metavar="", - help=_("UUID or name of the port group " - "(or MAC address if --address is specified).")) - parser.add_argument( - '--address', - dest='address', - action='store_true', - default=False, - help=_(' is the MAC address (instead of UUID or name) ' - 'of the port group.')) - parser.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - choices=res_fields.PORTGROUP_DETAILED_RESOURCE.fields, - default=[], - help=_("One or more port group fields. Only these fields will be " - "fetched from the server.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - fields = list(itertools.chain.from_iterable(parsed_args.fields)) - fields = fields if fields else None - - if parsed_args.address: - portgroup = baremetal_client.portgroup.get_by_address( - parsed_args.portgroup, fields=fields)._info - else: - portgroup = baremetal_client.portgroup.get( - parsed_args.portgroup, fields=fields)._info - - portgroup.pop("links", None) - portgroup.pop("ports", None) - return zip(*sorted(portgroup.items())) - - -class ListBaremetalPortGroup(command.Lister): - """List baremetal port groups.""" - - log = logging.getLogger(__name__ + ".ListBaremetalPortGroup") - - def get_parser(self, prog_name): - parser = super(ListBaremetalPortGroup, self).get_parser(prog_name) - parser.add_argument( - '--limit', - metavar='', - type=int, - help=_('Maximum number of port groups to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Baremetal API Service.')) - parser.add_argument( - '--marker', - metavar='', - help=_('Port group UUID (for example, of the last port group in ' - 'the list from a previous request). Returns the list of ' - 'port groups after this UUID.')) - parser.add_argument( - '--sort', - metavar="[:]", - help=_('Sort output by specified port group fields and directions ' - '(asc or desc) (default: asc). Multiple fields and ' - 'directions can be specified, separated by comma.')) - parser.add_argument( - '--address', - metavar='', - help=_("Only show information for the port group with this MAC " - "address.")) - parser.add_argument( - '--node', - dest='node', - metavar='', - help=_("Only list port groups of this node (name or UUID).")) - - display_group = parser.add_mutually_exclusive_group(required=False) - display_group.add_argument( - '--long', - default=False, - dest='detail', - help=_("Show detailed information about the port groups."), - action='store_true') - display_group.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - choices=res_fields.PORTGROUP_DETAILED_RESOURCE.fields, - help=_("One or more port group fields. Only these fields will be " - "fetched from the server. Can not be used when '--long' is " - "specified.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - client = self.app.client_manager.baremetal - - columns = res_fields.PORTGROUP_RESOURCE.fields - labels = res_fields.PORTGROUP_RESOURCE.labels - - params = {} - if parsed_args.limit is not None and parsed_args.limit < 0: - raise exc.CommandError( - _('Expected non-negative --limit, got %s') % - parsed_args.limit) - params['limit'] = parsed_args.limit - params['marker'] = parsed_args.marker - if parsed_args.address is not None: - params['address'] = parsed_args.address - if parsed_args.node is not None: - params['node'] = parsed_args.node - - if parsed_args.detail: - params['detail'] = parsed_args.detail - columns = res_fields.PORTGROUP_DETAILED_RESOURCE.fields - labels = res_fields.PORTGROUP_DETAILED_RESOURCE.labels - elif parsed_args.fields: - params['detail'] = False - fields = itertools.chain.from_iterable(parsed_args.fields) - resource = res_fields.Resource(list(fields)) - columns = resource.fields - labels = resource.labels - params['fields'] = columns - - self.log.debug("params(%s)", params) - data = client.portgroup.list(**params) - - data = oscutils.sort_items(data, parsed_args.sort) - - return (labels, - (oscutils.get_item_properties(s, columns, formatters={ - 'Properties': oscutils.format_dict},) for s in data)) - - -class DeleteBaremetalPortGroup(command.Command): - """Unregister baremetal port group(s).""" - - log = logging.getLogger(__name__ + ".DeleteBaremetalPortGroup") - - def get_parser(self, prog_name): - parser = super(DeleteBaremetalPortGroup, self).get_parser(prog_name) - parser.add_argument( - "portgroups", - metavar="", - nargs="+", - help=_("Port group(s) to delete (name or UUID).")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - failures = [] - for portgroup in parsed_args.portgroups: - try: - baremetal_client.portgroup.delete(portgroup) - print(_('Deleted port group %s') % portgroup) - except exc.ClientException as e: - failures.append(_("Failed to delete port group %(portgroup)s: " - " %(error)s") - % {'portgroup': portgroup, 'error': e}) - - if failures: - raise exc.ClientException("\n".join(failures)) - - -class SetBaremetalPortGroup(command.Command): - """Set baremetal port group properties.""" - - log = logging.getLogger(__name__ + ".SetBaremetalPortGroup") - - def get_parser(self, prog_name): - parser = super(SetBaremetalPortGroup, self).get_parser(prog_name) - - parser.add_argument( - 'portgroup', - metavar='', - help=_("Name or UUID of the port group."), - ) - parser.add_argument( - '--node', - dest='node_uuid', - metavar='', - help=_('Update UUID of the node that this port group belongs to.') - ) - parser.add_argument( - "--address", - metavar="", - help=_("MAC address for this port group."), - ) - parser.add_argument( - "--name", - metavar="", - help=_("Name of the port group."), - ) - parser.add_argument( - "--extra", - metavar="", - action='append', - help=_('Extra to set on this baremetal port group ' - '(repeat option to set multiple extras).'), - ) - parser.add_argument( - '--mode', - help=_('Mode of the port group. For possible values, refer to ' - 'https://www.kernel.org/doc/Documentation/networking' - '/bonding.txt.')) - parser.add_argument( - '--property', - dest='properties', - metavar="", - action='append', - help=_("Key/value property related to this port group's " - "configuration (repeat option to set multiple " - "properties).")) - standalone_ports_group = parser.add_mutually_exclusive_group() - standalone_ports_group.add_argument( - '--support-standalone-ports', - action='store_true', - default=None, - help=_("Ports that are members of this port group " - "can be used as stand-alone ports.") - ) - standalone_ports_group.add_argument( - '--unsupport-standalone-ports', - action='store_true', - help=_("Ports that are members of this port group " - "cannot be used as stand-alone ports.") - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - properties = [] - if parsed_args.node_uuid: - properties.extend(utils.args_array_to_patch( - 'add', ["node_uuid=%s" % parsed_args.node_uuid])) - if parsed_args.address: - properties.extend(utils.args_array_to_patch( - 'add', ["address=%s" % parsed_args.address])) - if parsed_args.name: - name = ["name=%s" % parsed_args.name] - properties.extend(utils.args_array_to_patch( - 'add', name)) - if parsed_args.support_standalone_ports: - properties.extend(utils.args_array_to_patch( - 'add', ["standalone_ports_supported=True"])) - if parsed_args.unsupport_standalone_ports: - properties.extend(utils.args_array_to_patch( - 'add', ["standalone_ports_supported=False"])) - if parsed_args.mode: - properties.extend(utils.args_array_to_patch( - 'add', ["mode=%s" % parsed_args.mode])) - - if parsed_args.extra: - properties.extend(utils.args_array_to_patch( - 'add', ['extra/' + x for x in parsed_args.extra])) - if parsed_args.properties: - properties.extend(utils.args_array_to_patch( - 'add', ['properties/' + x for x in parsed_args.properties])) - - if properties: - baremetal_client.portgroup.update(parsed_args.portgroup, - properties) - else: - self.log.warning("Please specify what to set.") - - -class UnsetBaremetalPortGroup(command.Command): - """Unset baremetal port group properties.""" - log = logging.getLogger(__name__ + ".UnsetBaremetalPortGroup") - - def get_parser(self, prog_name): - parser = super(UnsetBaremetalPortGroup, self).get_parser(prog_name) - - parser.add_argument( - 'portgroup', - metavar='', - help=_("Name or UUID of the port group.") - ) - parser.add_argument( - "--name", - action='store_true', - help=_("Unset the name of the port group."), - ) - parser.add_argument( - "--address", - action='store_true', - help=_("Unset the address of the port group."), - ) - parser.add_argument( - "--extra", - metavar="", - action='append', - help=_('Extra to unset on this baremetal port group ' - '(repeat option to unset multiple extras).'), - ) - parser.add_argument( - "--property", - dest='properties', - metavar="", - action='append', - help=_('Property to unset on this baremetal port group ' - '(repeat option to unset multiple properties).'), - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - properties = [] - if parsed_args.name: - properties.extend(utils.args_array_to_patch('remove', - ['name'])) - if parsed_args.address: - properties.extend(utils.args_array_to_patch('remove', - ['address'])) - if parsed_args.extra: - properties.extend(utils.args_array_to_patch('remove', - ['extra/' + x for x in parsed_args.extra])) - if parsed_args.properties: - properties.extend(utils.args_array_to_patch( - 'remove', ['properties/' + x for x in parsed_args.properties])) - - if properties: - baremetal_client.portgroup.update(parsed_args.portgroup, - properties) - else: - self.log.warning("Please specify what to unset.") diff --git a/ironicclient/osc/v1/baremetal_volume_connector.py b/ironicclient/osc/v1/baremetal_volume_connector.py deleted file mode 100644 index ec9299f..0000000 --- a/ironicclient/osc/v1/baremetal_volume_connector.py +++ /dev/null @@ -1,362 +0,0 @@ -# Copyright 2017 FUJITSU LIMITED -# -# 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 itertools -import logging - -from osc_lib.command import command -from osc_lib import utils as oscutils - -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.v1 import resource_fields as res_fields - - -class CreateBaremetalVolumeConnector(command.ShowOne): - """Create a new baremetal volume connector.""" - - log = logging.getLogger(__name__ + ".CreateBaremetalVolumeConnector") - - def get_parser(self, prog_name): - parser = ( - super(CreateBaremetalVolumeConnector, self).get_parser(prog_name)) - - parser.add_argument( - '--node', - dest='node_uuid', - metavar='', - required=True, - help=_('UUID of the node that this volume connector belongs to.')) - parser.add_argument( - '--type', - dest='type', - metavar="", - required=True, - choices=('iqn', 'ip', 'mac', 'wwnn', 'wwpn'), - help=_("Type of the volume connector. Can be 'iqn', 'ip', 'mac', " - "'wwnn', 'wwpn'.")) - parser.add_argument( - '--connector-id', - dest='connector_id', - required=True, - metavar="", - help=_("ID of the volume connector in the specified type. For " - "example, the iSCSI initiator IQN for the node if the type " - "is 'iqn'.")) - parser.add_argument( - '--uuid', - dest='uuid', - metavar='', - help=_("UUID of the volume connector.")) - parser.add_argument( - '--extra', - dest='extra', - metavar="", - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - baremetal_client = self.app.client_manager.baremetal - - field_list = ['extra', 'type', 'connector_id', 'node_uuid', 'uuid'] - fields = dict((k, v) for (k, v) in vars(parsed_args).items() - if k in field_list and v is not None) - fields = utils.args_array_to_dict(fields, 'extra') - volume_connector = baremetal_client.volume_connector.create(**fields) - - data = dict([(f, getattr(volume_connector, f, '')) for f in - res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.fields]) - return self.dict2columns(data) - - -class ShowBaremetalVolumeConnector(command.ShowOne): - """Show baremetal volume connector details.""" - - log = logging.getLogger(__name__ + ".ShowBaremetalVolumeConnector") - - def get_parser(self, prog_name): - parser = ( - super(ShowBaremetalVolumeConnector, self).get_parser(prog_name)) - - parser.add_argument( - 'volume_connector', - metavar='', - help=_("UUID of the volume connector.")) - parser.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - choices=res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.fields, - default=[], - help=_("One or more volume connector fields. Only these fields " - "will be fetched from the server.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - fields = list(itertools.chain.from_iterable(parsed_args.fields)) - fields = fields if fields else None - - volume_connector = baremetal_client.volume_connector.get( - parsed_args.volume_connector, fields=fields)._info - - volume_connector.pop("links", None) - return zip(*sorted(volume_connector.items())) - - -class ListBaremetalVolumeConnector(command.Lister): - """List baremetal volume connectors.""" - - log = logging.getLogger(__name__ + ".ListBaremetalVolumeConnector") - - def get_parser(self, prog_name): - parser = ( - super(ListBaremetalVolumeConnector, self).get_parser(prog_name)) - - parser.add_argument( - '--node', - dest='node', - metavar='', - help=_("Only list volume connectors of this node (name or UUID).")) - parser.add_argument( - '--limit', - dest='limit', - metavar='', - type=int, - help=_('Maximum number of volume connectors to return per ' - 'request, 0 for no limit. Default is the maximum number ' - 'used by the Baremetal API Service.')) - parser.add_argument( - '--marker', - dest='marker', - metavar='', - help=_('Volume connector UUID (for example, of the last volume ' - 'connector in the list from a previous request). Returns ' - 'the list of volume connectors after this UUID.')) - parser.add_argument( - '--sort', - dest='sort', - metavar='[:]', - help=_('Sort output by specified volume connector fields and ' - 'directions (asc or desc) (default:asc). Multiple fields ' - 'and directions can be specified, separated by comma.')) - - display_group = parser.add_mutually_exclusive_group(required=False) - display_group.add_argument( - '--long', - dest='detail', - action='store_true', - default=False, - help=_("Show detailed information about volume connectors.")) - display_group.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - choices=res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.fields, - help=_("One or more volume connector fields. Only these fields " - "will be fetched from the server. Can not be used when " - "'--long' is specified.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - client = self.app.client_manager.baremetal - - columns = res_fields.VOLUME_CONNECTOR_RESOURCE.fields - labels = res_fields.VOLUME_CONNECTOR_RESOURCE.labels - - params = {} - if parsed_args.limit is not None and parsed_args.limit < 0: - raise exc.CommandError( - _('Expected non-negative --limit, got %s') % - parsed_args.limit) - params['limit'] = parsed_args.limit - params['marker'] = parsed_args.marker - if parsed_args.node is not None: - params['node'] = parsed_args.node - - if parsed_args.detail: - params['detail'] = parsed_args.detail - columns = res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.fields - labels = res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.labels - elif parsed_args.fields: - params['detail'] = False - fields = itertools.chain.from_iterable(parsed_args.fields) - resource = res_fields.Resource(list(fields)) - columns = resource.fields - labels = resource.labels - params['fields'] = columns - - self.log.debug("params(%s)" % params) - data = client.volume_connector.list(**params) - - data = oscutils.sort_items(data, parsed_args.sort) - - return (labels, - (oscutils.get_item_properties(s, columns, formatters={ - 'Properties': oscutils.format_dict},) for s in data)) - - -class DeleteBaremetalVolumeConnector(command.Command): - """Unregister baremetal volume connector(s).""" - - log = logging.getLogger(__name__ + ".DeleteBaremetalVolumeConnector") - - def get_parser(self, prog_name): - parser = ( - super(DeleteBaremetalVolumeConnector, self).get_parser(prog_name)) - parser.add_argument( - 'volume_connectors', - metavar='', - nargs='+', - help=_("UUID(s) of the volume connector(s) to delete.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - failures = [] - for volume_connector in parsed_args.volume_connectors: - try: - baremetal_client.volume_connector.delete(volume_connector) - print(_('Deleted volume connector %s') % volume_connector) - except exc.ClientException as e: - failures.append(_("Failed to delete volume connector " - "%(volume_connector)s: %(error)s") - % {'volume_connector': volume_connector, - 'error': e}) - - if failures: - raise exc.ClientException("\n".join(failures)) - - -class SetBaremetalVolumeConnector(command.Command): - """Set baremetal volume connector properties.""" - - log = logging.getLogger(__name__ + ".SetBaremetalVolumeConnector") - - def get_parser(self, prog_name): - parser = ( - super(SetBaremetalVolumeConnector, self).get_parser(prog_name)) - - parser.add_argument( - 'volume_connector', - metavar='', - help=_("UUID of the volume connector.")) - parser.add_argument( - '--node', - dest='node_uuid', - metavar='', - help=_('UUID of the node that this volume connector belongs to.')) - parser.add_argument( - '--type', - dest='type', - metavar="", - choices=('iqn', 'ip', 'mac', 'wwnn', 'wwpn'), - help=_("Type of the volume connector. Can be 'iqn', 'ip', 'mac', " - "'wwnn', 'wwpn'.")) - parser.add_argument( - '--connector-id', - dest='connector_id', - metavar="", - help=_("ID of the volume connector in the specified type.")) - parser.add_argument( - '--extra', - dest='extra', - metavar="", - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - properties = [] - if parsed_args.node_uuid: - properties.extend(utils.args_array_to_patch( - 'add', ["node_uuid=%s" % parsed_args.node_uuid])) - if parsed_args.type: - properties.extend(utils.args_array_to_patch( - 'add', ["type=%s" % parsed_args.type])) - if parsed_args.connector_id: - properties.extend(utils.args_array_to_patch( - 'add', ["connector_id=%s" % parsed_args.connector_id])) - - if parsed_args.extra: - properties.extend(utils.args_array_to_patch( - 'add', ["extra/" + x for x in parsed_args.extra])) - - if properties: - baremetal_client.volume_connector.update( - parsed_args.volume_connector, properties) - else: - self.log.warning("Please specify what to set.") - - -class UnsetBaremetalVolumeConnector(command.Command): - """Unset baremetal volume connector properties.""" - log = logging.getLogger(__name__ + "UnsetBaremetalVolumeConnector") - - def get_parser(self, prog_name): - parser = ( - super(UnsetBaremetalVolumeConnector, self).get_parser(prog_name)) - - parser.add_argument( - 'volume_connector', - metavar='', - help=_("UUID of the volume connector.")) - parser.add_argument( - '--extra', - dest='extra', - metavar="", - action='append', - help=_('Extra to unset (repeat option to unset multiple extras)')) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - properties = [] - if parsed_args.extra: - properties.extend(utils.args_array_to_patch('remove', - ['extra/' + x for x in parsed_args.extra])) - - if properties: - baremetal_client.volume_connector.update( - parsed_args.volume_connector, properties) - else: - self.log.warning("Please specify what to unset.") diff --git a/ironicclient/osc/v1/baremetal_volume_target.py b/ironicclient/osc/v1/baremetal_volume_target.py deleted file mode 100644 index 9be5c7d..0000000 --- a/ironicclient/osc/v1/baremetal_volume_target.py +++ /dev/null @@ -1,412 +0,0 @@ -# Copyright 2017 FUJITSU LIMITED -# -# 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 itertools -import logging - -from osc_lib.command import command -from osc_lib import utils as oscutils - -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.v1 import resource_fields as res_fields - - -class CreateBaremetalVolumeTarget(command.ShowOne): - """Create a new baremetal volume target.""" - - log = logging.getLogger(__name__ + ".CreateBaremetalVolumeTarget") - - def get_parser(self, prog_name): - parser = super(CreateBaremetalVolumeTarget, self).get_parser(prog_name) - - parser.add_argument( - '--node', - dest='node_uuid', - metavar='', - required=True, - help=_('UUID of the node that this volume target belongs to.')) - parser.add_argument( - '--type', - dest='volume_type', - metavar="", - required=True, - help=_("Type of the volume target, e.g. 'iscsi', 'fibre_channel', " - "'rbd'.")) - parser.add_argument( - '--property', - dest='properties', - metavar="", - action='append', - help=_("Key/value property related to the type of this volume " - "target. Can be specified multiple times." - )) - parser.add_argument( - '--boot-index', - dest='boot_index', - metavar="", - type=int, - required=True, - help=_("Boot index of the volume target.")) - parser.add_argument( - '--volume-id', - dest='volume_id', - metavar="", - required=True, - help=_("ID of the volume associated with this target.")) - parser.add_argument( - '--uuid', - dest='uuid', - metavar='', - help=_("UUID of the volume target.")) - parser.add_argument( - '--extra', - dest='extra', - metavar="", - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - baremetal_client = self.app.client_manager.baremetal - - if parsed_args.boot_index < 0: - raise exc.CommandError( - _('Expected non-negative --boot-index, got %s') % - parsed_args.boot_index) - - field_list = ['extra', 'volume_type', 'properties', - 'boot_index', 'node_uuid', 'volume_id', 'uuid'] - fields = dict((k, v) for (k, v) in vars(parsed_args).items() - if k in field_list and v is not None) - fields = utils.args_array_to_dict(fields, 'properties') - fields = utils.args_array_to_dict(fields, 'extra') - volume_target = baremetal_client.volume_target.create(**fields) - - data = dict([(f, getattr(volume_target, f, '')) for f in - res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields]) - return self.dict2columns(data) - - -class ShowBaremetalVolumeTarget(command.ShowOne): - """Show baremetal volume target details.""" - - log = logging.getLogger(__name__ + ".ShowBaremetalVolumeTarget") - - def get_parser(self, prog_name): - parser = super(ShowBaremetalVolumeTarget, self).get_parser(prog_name) - - parser.add_argument( - 'volume_target', - metavar='', - help=_("UUID of the volume target.")) - parser.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - choices=res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields, - help=_("One or more volume target fields. Only these fields will " - "be fetched from the server.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - fields = list(itertools.chain.from_iterable(parsed_args.fields)) - fields = fields if fields else None - - volume_target = baremetal_client.volume_target.get( - parsed_args.volume_target, fields=fields)._info - - volume_target.pop("links", None) - return zip(*sorted(volume_target.items())) - - -class ListBaremetalVolumeTarget(command.Lister): - """List baremetal volume targets.""" - - log = logging.getLogger(__name__ + ".ListBaremetalVolumeTarget") - - def get_parser(self, prog_name): - parser = super(ListBaremetalVolumeTarget, self).get_parser(prog_name) - - parser.add_argument( - '--node', - dest='node', - metavar='', - help=_("Only list volume targets of this node (name or UUID).")) - parser.add_argument( - '--limit', - dest='limit', - metavar='', - type=int, - help=_('Maximum number of volume targets to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Baremetal API Service.')) - parser.add_argument( - '--marker', - dest='marker', - metavar='', - help=_('Volume target UUID (for example, of the last ' - 'volume target in the list from a previous request). ' - 'Returns the list of volume targets after this UUID.')) - parser.add_argument( - '--sort', - dest='sort', - metavar='[:]', - help=_('Sort output by specified volume target fields and ' - 'directions (asc or desc) (default:asc). Multiple fields ' - 'and directions can be specified, separated by comma.')) - - display_group = parser.add_mutually_exclusive_group(required=False) - display_group.add_argument( - '--long', - dest='detail', - action='store_true', - default=False, - help=_("Show detailed information about volume targets.")) - display_group.add_argument( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - choices=res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields, - help=_("One or more volume target fields. Only these fields will " - "be fetched from the server. Can not be used when " - "'--long' is specified.")) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - client = self.app.client_manager.baremetal - - columns = res_fields.VOLUME_TARGET_RESOURCE.fields - labels = res_fields.VOLUME_TARGET_RESOURCE.labels - - params = {} - if parsed_args.limit is not None and parsed_args.limit < 0: - raise exc.CommandError( - _('Expected non-negative --limit, got %s') % - parsed_args.limit) - params['limit'] = parsed_args.limit - params['marker'] = parsed_args.marker - if parsed_args.node is not None: - params['node'] = parsed_args.node - - if parsed_args.detail: - params['detail'] = parsed_args.detail - columns = res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields - labels = res_fields.VOLUME_TARGET_DETAILED_RESOURCE.labels - elif parsed_args.fields: - params['detail'] = False - fields = itertools.chain.from_iterable(parsed_args.fields) - resource = res_fields.Resource(list(fields)) - columns = resource.fields - labels = resource.labels - params['fields'] = columns - - self.log.debug("params(%s)" % params) - data = client.volume_target.list(**params) - - data = oscutils.sort_items(data, parsed_args.sort) - - return (labels, - (oscutils.get_item_properties(s, columns, formatters={ - 'Properties': oscutils.format_dict},) for s in data)) - - -class DeleteBaremetalVolumeTarget(command.Command): - """Unregister baremetal volume target(s).""" - - log = logging.getLogger(__name__ + ".DeleteBaremetalVolumeTarget") - - def get_parser(self, prog_name): - parser = ( - super(DeleteBaremetalVolumeTarget, self).get_parser(prog_name)) - parser.add_argument( - 'volume_targets', - metavar='', - nargs='+', - help=_("UUID(s) of the volume target(s) to delete.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - failures = [] - for volume_target in parsed_args.volume_targets: - try: - baremetal_client.volume_target.delete(volume_target) - print(_('Deleted volume target %s') % volume_target) - except exc.ClientException as e: - failures.append(_("Failed to delete volume target " - "%(volume_target)s: %(error)s") - % {'volume_target': volume_target, - 'error': e}) - - if failures: - raise exc.ClientException("\n".join(failures)) - - -class SetBaremetalVolumeTarget(command.Command): - """Set baremetal volume target properties.""" - - log = logging.getLogger(__name__ + ".SetBaremetalVolumeTarget") - - def get_parser(self, prog_name): - parser = ( - super(SetBaremetalVolumeTarget, self).get_parser(prog_name)) - - parser.add_argument( - 'volume_target', - metavar='', - help=_("UUID of the volume target.")) - parser.add_argument( - '--node', - dest='node_uuid', - metavar='', - help=_('UUID of the node that this volume target belongs to.')) - parser.add_argument( - '--type', - dest='volume_type', - metavar="", - help=_("Type of the volume target, e.g. 'iscsi', 'fibre_channel', " - "'rbd'.")) - parser.add_argument( - '--property', - dest='properties', - metavar="", - action='append', - help=_("Key/value property related to the type of this volume " - "target. Can be specified multiple times.")) - parser.add_argument( - '--boot-index', - dest='boot_index', - metavar="", - type=int, - help=_("Boot index of the volume target.")) - parser.add_argument( - '--volume-id', - dest='volume_id', - metavar="", - help=_("ID of the volume associated with this target.")) - parser.add_argument( - '--extra', - dest='extra', - metavar="", - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.")) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - if parsed_args.boot_index is not None and parsed_args.boot_index < 0: - raise exc.CommandError( - _('Expected non-negative --boot-index, got %s') % - parsed_args.boot_index) - - properties = [] - if parsed_args.node_uuid: - properties.extend(utils.args_array_to_patch( - 'add', ["node_uuid=%s" % parsed_args.node_uuid])) - if parsed_args.volume_type: - properties.extend(utils.args_array_to_patch( - 'add', ["volume_type=%s" % parsed_args.volume_type])) - if parsed_args.boot_index: - properties.extend(utils.args_array_to_patch( - 'add', ["boot_index=%s" % parsed_args.boot_index])) - if parsed_args.volume_id: - properties.extend(utils.args_array_to_patch( - 'add', ["volume_id=%s" % parsed_args.volume_id])) - - if parsed_args.properties: - properties.extend(utils.args_array_to_patch( - 'add', ["properties/" + x for x in parsed_args.properties])) - if parsed_args.extra: - properties.extend(utils.args_array_to_patch( - 'add', ["extra/" + x for x in parsed_args.extra])) - - if properties: - baremetal_client.volume_target.update( - parsed_args.volume_target, properties) - else: - self.log.warning("Please specify what to set.") - - -class UnsetBaremetalVolumeTarget(command.Command): - """Unset baremetal volume target properties.""" - log = logging.getLogger(__name__ + "UnsetBaremetalVolumeTarget") - - def get_parser(self, prog_name): - parser = ( - super(UnsetBaremetalVolumeTarget, self).get_parser(prog_name)) - - parser.add_argument( - 'volume_target', - metavar='', - help=_("UUID of the volume target.")) - parser.add_argument( - '--extra', - dest='extra', - metavar="", - action='append', - help=_('Extra to unset (repeat option to unset multiple extras)')) - parser.add_argument( - "--property", - dest='properties', - metavar="", - action='append', - help='Property to unset on this baremetal volume target ' - '(repeat option to unset multiple properties).', - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - baremetal_client = self.app.client_manager.baremetal - - properties = [] - if parsed_args.extra: - properties.extend(utils.args_array_to_patch('remove', - ['extra/' + x for x in parsed_args.extra])) - if parsed_args.properties: - properties.extend(utils.args_array_to_patch( - 'remove', ['properties/' + x for x in parsed_args.properties])) - - if properties: - baremetal_client.volume_target.update( - parsed_args.volume_target, properties) - else: - self.log.warning("Please specify what to unset.") diff --git a/ironicclient/shell.py b/ironicclient/shell.py deleted file mode 100644 index df7c54f..0000000 --- a/ironicclient/shell.py +++ /dev/null @@ -1,460 +0,0 @@ -# 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. - -""" -Command-line interface to the OpenStack Bare Metal Provisioning API. -""" - -from __future__ import print_function - -import argparse -import getpass -import logging -import os -import pkgutil -import re -import sys - -from keystoneauth1.loading import session as kasession -from oslo_utils import encodeutils -from oslo_utils import importutils -import six - -import ironicclient -from ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common import http -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc - - -LATEST_API_VERSION = ('1', 'latest') -MISSING_VERSION_WARNING = ( - "You are using the default API version of the 'ironic' command. " - "This is currently API version %s. In the future, the default will be " - "the latest API version understood by both API and CLI. You can preserve " - "the current behavior by passing the --ironic-api-version argument with " - "the desired version or using the IRONIC_API_VERSION environment variable." -) - - -class IronicShell(object): - - def get_base_parser(self): - parser = argparse.ArgumentParser( - prog='ironic', - description=__doc__.strip(), - epilog=_('See "ironic help COMMAND" ' - 'for help on a specific command.'), - add_help=False, - formatter_class=HelpFormatter, - ) - - # Register global Keystone args first so their defaults are respected. - # See https://bugs.launchpad.net/python-ironicclient/+bug/1463581 - kasession.register_argparse_arguments(parser) - - # Global arguments - parser.add_argument('-h', '--help', - action='store_true', - help=argparse.SUPPRESS, - ) - - parser.add_argument('--version', - action='version', - version=ironicclient.__version__) - - parser.add_argument('--debug', - default=bool(cliutils.env('IRONICCLIENT_DEBUG')), - action='store_true', - help=_('Defaults to env[IRONICCLIENT_DEBUG]')) - - parser.add_argument('--json', - default=False, - action='store_true', - help=_('Print JSON response without formatting.')) - - parser.add_argument('-v', '--verbose', - default=False, action="store_true", - help=_('Print more verbose output')) - - # for backward compatibility only - parser.add_argument('--cert-file', - dest='os_cert', - help=_('DEPRECATED! Use --os-cert.')) - - # for backward compatibility only - parser.add_argument('--key-file', - dest='os_key', - help=_('DEPRECATED! Use --os-key.')) - - # for backward compatibility only - parser.add_argument('--ca-file', - dest='os_cacert', - help=_('DEPRECATED! Use --os-cacert.')) - - parser.add_argument('--os-username', - default=cliutils.env('OS_USERNAME'), - help=_('Defaults to env[OS_USERNAME]')) - - parser.add_argument('--os_username', - help=argparse.SUPPRESS) - - parser.add_argument('--os-password', - default=cliutils.env('OS_PASSWORD'), - help=_('Defaults to env[OS_PASSWORD]')) - - parser.add_argument('--os_password', - help=argparse.SUPPRESS) - - parser.add_argument('--os-tenant-id', - default=cliutils.env('OS_TENANT_ID'), - help=_('Defaults to env[OS_TENANT_ID]')) - - parser.add_argument('--os_tenant_id', - help=argparse.SUPPRESS) - - parser.add_argument('--os-tenant-name', - default=cliutils.env('OS_TENANT_NAME'), - help=_('Defaults to env[OS_TENANT_NAME]')) - - parser.add_argument('--os_tenant_name', - help=argparse.SUPPRESS) - - parser.add_argument('--os-auth-url', - default=cliutils.env('OS_AUTH_URL'), - help=_('Defaults to env[OS_AUTH_URL]')) - - parser.add_argument('--os_auth_url', - help=argparse.SUPPRESS) - - parser.add_argument('--os-region-name', - default=cliutils.env('OS_REGION_NAME'), - help=_('Defaults to env[OS_REGION_NAME]')) - - parser.add_argument('--os_region_name', - help=argparse.SUPPRESS) - - parser.add_argument('--os-auth-token', - default=cliutils.env('OS_AUTH_TOKEN'), - help=_('Defaults to env[OS_AUTH_TOKEN]')) - - parser.add_argument('--os_auth_token', - help=argparse.SUPPRESS) - - parser.add_argument('--ironic-url', - default=cliutils.env('IRONIC_URL'), - help=_('Defaults to env[IRONIC_URL]')) - - parser.add_argument('--ironic_url', - help=argparse.SUPPRESS) - - parser.add_argument('--ironic-api-version', - default=cliutils.env('IRONIC_API_VERSION', - default=None), - help=_('Accepts 1.x (where "x" is microversion) ' - 'or "latest". Defaults to ' - 'env[IRONIC_API_VERSION] or %s. Starting ' - 'with the Queens release this will ' - 'default to "latest".') % http.DEFAULT_VER) - - parser.add_argument('--ironic_api_version', - help=argparse.SUPPRESS) - - parser.add_argument('--os-service-type', - default=cliutils.env('OS_SERVICE_TYPE'), - help=_('Defaults to env[OS_SERVICE_TYPE] or ' - '"baremetal"')) - - parser.add_argument('--os_service_type', - help=argparse.SUPPRESS) - - parser.add_argument('--os-endpoint', - dest='ironic_url', - default=cliutils.env('OS_SERVICE_ENDPOINT'), - help=_('Specify an endpoint to use instead of ' - 'retrieving one from the service catalog ' - '(via authentication). ' - 'Defaults to env[OS_SERVICE_ENDPOINT].')) - - parser.add_argument('--os_endpoint', - dest='ironic_url', - help=argparse.SUPPRESS) - - parser.add_argument('--os-endpoint-type', - default=cliutils.env('OS_ENDPOINT_TYPE'), - help=_('Defaults to env[OS_ENDPOINT_TYPE] or ' - '"publicURL"')) - - parser.add_argument('--os_endpoint_type', - help=argparse.SUPPRESS) - - parser.add_argument('--os-user-domain-id', - default=cliutils.env('OS_USER_DOMAIN_ID'), - help=_('Defaults to env[OS_USER_DOMAIN_ID].')) - - parser.add_argument('--os-user-domain-name', - default=cliutils.env('OS_USER_DOMAIN_NAME'), - help=_('Defaults to env[OS_USER_DOMAIN_NAME].')) - - parser.add_argument('--os-project-id', - default=cliutils.env('OS_PROJECT_ID'), - help=_('Another way to specify tenant ID. ' - 'This option is mutually exclusive with ' - ' --os-tenant-id. ' - 'Defaults to env[OS_PROJECT_ID].')) - - parser.add_argument('--os-project-name', - default=cliutils.env('OS_PROJECT_NAME'), - help=_('Another way to specify tenant name. ' - 'This option is mutually exclusive with ' - ' --os-tenant-name. ' - 'Defaults to env[OS_PROJECT_NAME].')) - - parser.add_argument('--os-project-domain-id', - default=cliutils.env('OS_PROJECT_DOMAIN_ID'), - help=_('Defaults to env[OS_PROJECT_DOMAIN_ID].')) - - parser.add_argument('--os-project-domain-name', - default=cliutils.env('OS_PROJECT_DOMAIN_NAME'), - help=_('Defaults to env[OS_PROJECT_DOMAIN_NAME].')) - - msg = _('Maximum number of retries in case of conflict error ' - '(HTTP 409). Defaults to env[IRONIC_MAX_RETRIES] or %d. ' - 'Use 0 to disable retrying.') % http.DEFAULT_MAX_RETRIES - parser.add_argument('--max-retries', type=int, help=msg, - default=cliutils.env( - 'IRONIC_MAX_RETRIES', - default=str(http.DEFAULT_MAX_RETRIES))) - - msg = _('Amount of time (in seconds) between retries ' - 'in case of conflict error (HTTP 409). ' - 'Defaults to env[IRONIC_RETRY_INTERVAL] ' - 'or %d.') % http.DEFAULT_RETRY_INTERVAL - parser.add_argument('--retry-interval', type=int, help=msg, - default=cliutils.env( - 'IRONIC_RETRY_INTERVAL', - default=str(http.DEFAULT_RETRY_INTERVAL))) - - return parser - - def get_available_major_versions(self): - matcher = re.compile(r"^v[0-9]+$") - submodules = pkgutil.iter_modules([os.path.dirname(__file__)]) - available_versions = [name[1:] for loader, name, ispkg in submodules - if matcher.search(name)] - - return available_versions - - def get_subcommand_parser(self, version): - parser = self.get_base_parser() - - self.subcommands = {} - subparsers = parser.add_subparsers(metavar='', - dest='subparser_name') - try: - submodule = importutils.import_versioned_module('ironicclient', - version, 'shell') - except ImportError as e: - msg = _("Invalid client version '%(version)s'. " - "Major part must be one of: '%(major)s'") % { - "version": version, - "major": ", ".join(self.get_available_major_versions())} - raise exceptions.UnsupportedVersion( - _('%(message)s, error was: %(error)s') % - {'message': msg, 'error': e}) - submodule.enhance_parser(parser, subparsers, self.subcommands) - utils.define_commands_from_module(subparsers, self, self.subcommands) - return parser - - def _setup_debugging(self, debug): - if debug: - logging.basicConfig( - format="%(levelname)s (%(module)s:%(lineno)d) %(message)s", - level=logging.DEBUG) - else: - logging.basicConfig( - format="%(levelname)s %(message)s", - level=logging.CRITICAL) - - def do_bash_completion(self): - """Prints all of the commands and options for bash-completion.""" - commands = set() - options = set() - for sc_str, sc in self.subcommands.items(): - commands.add(sc_str) - for option in sc._optionals._option_string_actions.keys(): - options.add(option) - - commands.remove('bash-completion') - print(' '.join(commands | options)) - - def _check_version(self, api_version): - if api_version == 'latest': - return LATEST_API_VERSION - else: - if api_version is None: - print(MISSING_VERSION_WARNING % http.DEFAULT_VER, - file=sys.stderr) - api_version = '1' - - try: - versions = tuple(int(i) for i in api_version.split('.')) - except ValueError: - versions = () - if len(versions) == 1: - # Default value of ironic_api_version is '1'. - # If user not specify the value of api version, not passing - # headers at all. - os_ironic_api_version = None - elif len(versions) == 2: - os_ironic_api_version = api_version - # In the case of '1.0' - if versions[1] == 0: - os_ironic_api_version = None - else: - msg = _("The requested API version %(ver)s is an unexpected " - "format. Acceptable formats are 'X', 'X.Y', or the " - "literal string '%(latest)s'." - ) % {'ver': api_version, 'latest': 'latest'} - raise exc.CommandError(msg) - - api_major_version = versions[0] - return (api_major_version, os_ironic_api_version) - - def main(self, argv): - # Parse args once to find version - parser = self.get_base_parser() - (options, args) = parser.parse_known_args(argv) - self._setup_debugging(options.debug) - - # build available subcommands based on version - (api_major_version, os_ironic_api_version) = ( - self._check_version(options.ironic_api_version)) - - subcommand_parser = self.get_subcommand_parser(api_major_version) - self.parser = subcommand_parser - - # Handle top-level --help/-h before attempting to parse - # a command off the command line - if options.help or not argv: - self.do_help(options) - return 0 - - # Parse args again and call whatever callback was selected - args = subcommand_parser.parse_args(argv) - - # Short-circuit and deal with these commands right away. - if args.func == self.do_help: - self.do_help(args) - return 0 - elif args.func == self.do_bash_completion: - self.do_bash_completion() - return 0 - - if not (args.os_auth_token and (args.ironic_url or args.os_auth_url)): - if not args.os_username: - raise exc.CommandError(_("You must provide a username via " - "either --os-username or via " - "env[OS_USERNAME]")) - - if not args.os_password: - # No password, If we've got a tty, try prompting for it - if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty(): - # Check for Ctl-D - try: - args.os_password = getpass.getpass( - 'OpenStack Password: ') - except EOFError: - pass - # No password because we didn't have a tty or the - # user Ctl-D when prompted. - if not args.os_password: - raise exc.CommandError(_("You must provide a password via " - "either --os-password, " - "env[OS_PASSWORD], " - "or prompted response")) - - if not (args.os_tenant_id or args.os_tenant_name or - args.os_project_id or args.os_project_name): - raise exc.CommandError( - _("You must provide a project name or" - " project id via --os-project-name, --os-project-id," - " env[OS_PROJECT_ID] or env[OS_PROJECT_NAME]. You may" - " use os-project and os-tenant interchangeably.")) - - if not args.os_auth_url: - raise exc.CommandError(_("You must provide an auth url via " - "either --os-auth-url or via " - "env[OS_AUTH_URL]")) - - if args.max_retries < 0: - raise exc.CommandError(_("You must provide value >= 0 for " - "--max-retries")) - if args.retry_interval < 1: - raise exc.CommandError(_("You must provide value >= 1 for " - "--retry-interval")) - client_args = ( - 'os_auth_token', 'ironic_url', 'os_username', 'os_password', - 'os_auth_url', 'os_project_id', 'os_project_name', 'os_tenant_id', - 'os_tenant_name', 'os_region_name', 'os_user_domain_id', - 'os_user_domain_name', 'os_project_domain_id', - 'os_project_domain_name', 'os_service_type', 'os_endpoint_type', - 'os_cacert', 'os_cert', 'os_key', 'max_retries', 'retry_interval', - 'timeout', 'insecure' - ) - kwargs = {} - for key in client_args: - kwargs[key] = getattr(args, key) - kwargs['os_ironic_api_version'] = os_ironic_api_version - client = ironicclient.client.get_client(api_major_version, **kwargs) - - try: - args.func(client, args) - except exc.Unauthorized: - raise exc.CommandError(_("Invalid OpenStack Identity credentials")) - except exc.CommandError as e: - subcommand_parser = self.subcommands[args.subparser_name] - subcommand_parser.error(e) - - @cliutils.arg('command', metavar='', nargs='?', - help=_('Display help for ')) - def do_help(self, args): - """Display help about this program or one of its subcommands.""" - if getattr(args, 'command', None): - if args.command in self.subcommands: - self.subcommands[args.command].print_help() - else: - raise exc.CommandError(_("'%s' is not a valid subcommand") % - args.command) - else: - self.parser.print_help() - - -class HelpFormatter(argparse.HelpFormatter): - def start_section(self, heading): - super(HelpFormatter, self).start_section(heading.capitalize()) - - -def main(): - try: - IronicShell().main(sys.argv[1:]) - except KeyboardInterrupt: - print(_("... terminating ironic client"), file=sys.stderr) - return 130 - except Exception as e: - print(encodeutils.safe_encode(six.text_type(e)), file=sys.stderr) - return 1 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/ironicclient/tests/__init__.py b/ironicclient/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/functional/__init__.py b/ironicclient/tests/functional/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/functional/base.py b/ironicclient/tests/functional/base.py deleted file mode 100644 index a0ea61b..0000000 --- a/ironicclient/tests/functional/base.py +++ /dev/null @@ -1,445 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 os - -import six -import six.moves.configparser as config_parser -from tempest.lib.cli import base -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions - -import ironicclient.tests.functional.utils as utils - -DEFAULT_CONFIG_FILE = os.path.join(os.path.dirname(__file__), 'test.conf') - - -class FunctionalTestBase(base.ClientTestBase): - """Ironic base class, calls to ironicclient.""" - - def setUp(self): - super(FunctionalTestBase, self).setUp() - self.client = self._get_clients() - # NOTE(kromanenko) set ironic api version for portgroups - self.pg_api_ver = '--ironic-api-version 1.25' - - def _get_clients(self): - # NOTE(aarefiev): {toxinidir} is a current working directory, so - # the tox env path is {toxinidir}/.tox - cli_dir = os.path.join(os.path.abspath('.'), '.tox/functional/bin') - - config = self._get_config() - if config.get('os_auth_url'): - client = base.CLIClient(cli_dir=cli_dir, - username=config['os_username'], - password=config['os_password'], - tenant_name=config['os_project_name'], - uri=config['os_auth_url']) - for keystone_object in 'user', 'project': - domain_attr = 'os_%s_domain_id' % keystone_object - if config.get(domain_attr): - setattr(self, domain_attr, config[domain_attr]) - else: - self.ironic_url = config['ironic_url'] - self.os_auth_token = config['os_auth_token'] - client = base.CLIClient(cli_dir=cli_dir, - ironic_url=self.ironic_url, - os_auth_token=self.os_auth_token) - return client - - def _get_config(self): - config_file = os.environ.get('IRONICCLIENT_TEST_CONFIG', - DEFAULT_CONFIG_FILE) - # SafeConfigParser was deprecated in Python 3.2 - if six.PY3: - config = config_parser.ConfigParser() - else: - config = config_parser.SafeConfigParser() - if not config.read(config_file): - self.skipTest('Skipping, no test config found @ %s' % config_file) - try: - auth_strategy = config.get('functional', 'auth_strategy') - except config_parser.NoOptionError: - auth_strategy = 'keystone' - if auth_strategy not in ['keystone', 'noauth']: - raise self.fail( - 'Invalid auth type specified: %s in functional must be ' - 'one of: [keystone, noauth]' % auth_strategy) - - conf_settings = [] - keystone_v3_conf_settings = [] - if auth_strategy == 'keystone': - conf_settings += ['os_auth_url', 'os_username', - 'os_password', 'os_project_name'] - keystone_v3_conf_settings += ['os_user_domain_id', - 'os_project_domain_id'] - else: - conf_settings += ['os_auth_token', 'ironic_url'] - - cli_flags = {} - missing = [] - for c in conf_settings + keystone_v3_conf_settings: - try: - cli_flags[c] = config.get('functional', c) - except config_parser.NoOptionError: - # NOTE(vdrok): Here we ignore the absence of KS v3 options as - # v2 may be used. Keystone client will do the actual check of - # the parameters' correctness. - if c not in keystone_v3_conf_settings: - missing.append(c) - if missing: - self.fail('Missing required setting in test.conf (%(conf)s) for ' - 'auth_strategy=%(auth)s: %(missing)s' % - {'conf': config_file, - 'auth': auth_strategy, - 'missing': ','.join(missing)}) - return cli_flags - - def _cmd_no_auth(self, cmd, action, flags='', params=''): - """Execute given command with noauth attributes. - - :param cmd: command to be executed - :type cmd: string - :param action: command on cli to run - :type action: string - :param flags: optional cli flags to use - :type flags: string - :param params: optional positional args to use - :type params: string - """ - flags = ('--os_auth_token %(token)s --ironic_url %(url)s %(flags)s' - % - {'token': self.os_auth_token, - 'url': self.ironic_url, - 'flags': flags}) - return base.execute(cmd, action, flags, params, - cli_dir=self.client.cli_dir) - - def _ironic(self, action, flags='', params='', merge_stderr=False): - """Execute ironic command for the given action. - - :param action: the cli command to run using Ironic - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param merge_stderr: whether to merge stderr into the result - :type merge_stderr: bool - """ - flags += ' --os-endpoint-type publicURL' - if hasattr(self, 'os_auth_token'): - return self._cmd_no_auth('ironic', action, flags, params) - else: - for keystone_object in 'user', 'project': - domain_attr = 'os_%s_domain_id' % keystone_object - if hasattr(self, domain_attr): - flags += ' --os-%(ks_obj)s-domain-id %(value)s' % { - 'ks_obj': keystone_object, - 'value': getattr(self, domain_attr) - } - return self.client.cmd_with_auth('ironic', - action, flags, params, - merge_stderr=merge_stderr) - - def _ironic_osc(self, action, flags='', params='', merge_stderr=False): - """Execute baremetal commands via OpenStack Client.""" - config = self._get_config() - id_api_version = config.get('functional', 'os_identity_api_version') - flags += ' --os-identity-api-version {0}'.format(id_api_version) - - for keystone_object in 'user', 'project': - domain_attr = 'os_%s_domain_id' % keystone_object - if hasattr(self, domain_attr): - flags += ' --os-%(ks_obj)s-domain-id %(value)s' % { - 'ks_obj': keystone_object, - 'value': getattr(self, domain_attr) - } - return self.client.cmd_with_auth( - 'openstack', action, flags, params, merge_stderr=merge_stderr) - - def ironic(self, action, flags='', params='', parse=True): - """Return parsed list of dicts with basic item info. - - :param action: the cli command to run using Ironic - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param parse: return parsed list or raw output - :type parse: bool - """ - output = self._ironic(action=action, flags=flags, params=params) - return self.parser.listing(output) if parse else output - - def get_table_headers(self, action, flags='', params=''): - output = self._ironic(action=action, flags=flags, params=params) - table = self.parser.table(output) - return table['headers'] - - def assertTableHeaders(self, field_names, table_headers): - """Assert that field_names and table_headers are equal. - - :param field_names: field names from the output table of the cmd - :param table_headers: table headers output from cmd - """ - self.assertEqual(sorted(field_names), sorted(table_headers)) - - def assertNodeStates(self, node_show, node_show_states): - """Assert that node_show_states output corresponds to node_show output. - - :param node_show: output from node-show cmd - :param node_show_states: output from node-show-states cmd - """ - for key in node_show_states.keys(): - self.assertEqual(node_show_states[key], node_show[key]) - - def assertNodeValidate(self, node_validate): - """Assert that all interfaces present are valid. - - :param node_validate: output from node-validate cmd - """ - self.assertNotIn('False', [x['Result'] for x in node_validate]) - - def delete_node(self, node_id): - """Delete node method works only with fake driver. - - :param node_id: node uuid - :raises: CommandFailed exception when command fails to delete a node - """ - node_list = self.list_nodes() - - if utils.get_object(node_list, node_id): - node_show = self.show_node(node_id) - if node_show['provision_state'] != 'available': - self.ironic('node-set-provision-state', - params='{0} deleted'.format(node_id)) - if node_show['power_state'] not in ('None', 'off'): - self.ironic('node-set-power-state', - params='{0} off'.format(node_id)) - self.ironic('node-delete', params=node_id) - - node_list_uuid = self.get_nodes_uuids_from_node_list() - if node_id in node_list_uuid: - self.fail('Ironic node {0} has not been deleted!' - .format(node_id)) - - def create_node(self, driver='fake', params=''): - node = self.ironic('node-create', - params='--driver {0} {1}'.format(driver, params)) - - if not node: - self.fail('Ironic node has not been created!') - - node = utils.get_dict_from_output(node) - self.addCleanup(self.delete_node, node['uuid']) - return node - - def show_node(self, node_id, params=''): - node_show = self.ironic('node-show', - params='{0} {1}'.format(node_id, params)) - return utils.get_dict_from_output(node_show) - - def list_nodes(self, params=''): - return self.ironic('node-list', params=params) - - def update_node(self, node_id, params): - updated_node = self.ironic('node-update', - params='{0} {1}'.format(node_id, params)) - return utils.get_dict_from_output(updated_node) - - def get_nodes_uuids_from_node_list(self): - node_list = self.list_nodes() - return [x['UUID'] for x in node_list] - - def show_node_states(self, node_id): - show_node_states = self.ironic('node-show-states', params=node_id) - return utils.get_dict_from_output(show_node_states) - - def set_node_maintenance(self, node_id, maintenance_mode, params=''): - self.ironic( - 'node-set-maintenance', - params='{0} {1} {2}'.format(node_id, maintenance_mode, params)) - - def set_node_power_state(self, node_id, power_state, params=''): - self.ironic('node-set-power-state', - params='{0} {1} {2}' - .format(node_id, power_state, params)) - - def set_node_provision_state(self, node_id, provision_state, params=''): - self.ironic('node-set-provision-state', - params='{0} {1} {2}' - .format(node_id, provision_state, params)) - - def validate_node(self, node_id): - return self.ironic('node-validate', params=node_id) - - def list_node_chassis(self, chassis_uuid, params=''): - return self.ironic('chassis-node-list', - params='{0} {1}'.format(chassis_uuid, params)) - - def get_nodes_uuids_from_chassis_node_list(self, chassis_uuid): - chassis_node_list = self.list_node_chassis(chassis_uuid) - return [x['UUID'] for x in chassis_node_list] - - def list_driver(self, params=''): - return self.ironic('driver-list', params=params) - - def show_driver(self, driver_name): - driver_show = self.ironic('driver-show', params=driver_name) - return utils.get_dict_from_output(driver_show) - - def properties_driver(self, driver_name): - return self.ironic('driver-properties', params=driver_name) - - def get_drivers_names(self): - driver_list = self.list_driver() - return [x['Supported driver(s)'] for x in driver_list] - - def delete_chassis(self, chassis_id, ignore_exceptions=False): - try: - self.ironic('chassis-delete', params=chassis_id) - except exceptions.CommandFailed: - if not ignore_exceptions: - raise - - def get_chassis_uuids_from_chassis_list(self): - chassis_list = self.list_chassis() - return [x['UUID'] for x in chassis_list] - - def create_chassis(self, params=''): - chassis = self.ironic('chassis-create', params=params) - - if not chassis: - self.fail('Ironic chassis has not been created!') - - chassis = utils.get_dict_from_output(chassis) - self.addCleanup(self.delete_chassis, - chassis['uuid'], - ignore_exceptions=True) - return chassis - - def list_chassis(self, params=''): - return self.ironic('chassis-list', params=params) - - def show_chassis(self, chassis_id, params=''): - chassis_show = self.ironic('chassis-show', - params='{0} {1}'.format(chassis_id, params)) - return utils.get_dict_from_output(chassis_show) - - def update_chassis(self, chassis_id, operation, params=''): - updated_chassis = self.ironic( - 'chassis-update', - params='{0} {1} {2}'.format(chassis_id, operation, params)) - return utils.get_dict_from_output(updated_chassis) - - def delete_port(self, port_id, ignore_exceptions=False): - try: - self.ironic('port-delete', params=port_id) - except exceptions.CommandFailed: - if not ignore_exceptions: - raise - - def create_port(self, - node_id, - mac_address=None, - flags='', - params=''): - - if mac_address is None: - mac_address = data_utils.rand_mac_address() - - port = self.ironic('port-create', - flags=flags, - params='--address {0} --node {1} {2}' - .format(mac_address, node_id, params)) - if not port: - self.fail('Ironic port has not been created!') - - return utils.get_dict_from_output(port) - - def list_ports(self, params=''): - return self.ironic('port-list', params=params) - - def show_port(self, port_id, params=''): - port_show = self.ironic('port-show', params='{0} {1}' - .format(port_id, params)) - return utils.get_dict_from_output(port_show) - - def get_uuids_from_port_list(self): - port_list = self.list_ports() - return [x['UUID'] for x in port_list] - - def update_port(self, port_id, operation, flags='', params=''): - updated_port = self.ironic('port-update', - flags=flags, - params='{0} {1} {2}' - .format(port_id, operation, params)) - return utils.get_dict_from_output(updated_port) - - def create_portgroup(self, node_id, params=''): - """Create a new portgroup.""" - portgroup = self.ironic('portgroup-create', - flags=self.pg_api_ver, - params='--node {0} {1}' - .format(node_id, params)) - if not portgroup: - self.fail('Ironic portgroup failed to create!') - portgroup = utils.get_dict_from_output(portgroup) - self.addCleanup(self.delete_portgroup, portgroup['uuid'], - ignore_exceptions=True) - return portgroup - - def delete_portgroup(self, portgroup_id, ignore_exceptions=False): - """Delete a port group.""" - try: - self.ironic('portgroup-delete', - flags=self.pg_api_ver, - params=portgroup_id) - except exceptions.CommandFailed: - if not ignore_exceptions: - raise - - def list_portgroups(self, params=''): - """List the port groups.""" - return self.ironic('portgroup-list', - flags=self.pg_api_ver, - params=params) - - def show_portgroup(self, portgroup_id, params=''): - """Show detailed information about a port group.""" - portgroup_show = self.ironic('portgroup-show', - flags=self.pg_api_ver, - params='{0} {1}' - .format(portgroup_id, params)) - return utils.get_dict_from_output(portgroup_show) - - def update_portgroup(self, portgroup_id, op, params=''): - """Update information about a port group.""" - updated_portgroup = self.ironic('portgroup-update', - flags=self.pg_api_ver, - params='{0} {1} {2}' - .format(portgroup_id, op, params)) - return utils.get_dict_from_output(updated_portgroup) - - def get_portgroup_uuids_from_portgroup_list(self): - """Get UUIDs from list of port groups.""" - portgroup_list = self.list_portgroups() - return [x['UUID'] for x in portgroup_list] - - def portgroup_port_list(self, portgroup_id, params=''): - """List the ports associated with a port group.""" - return self.ironic('portgroup-port-list', flags=self.pg_api_ver, - params='{0} {1}'.format(portgroup_id, params)) diff --git a/ironicclient/tests/functional/hooks/post_test_hook.sh b/ironicclient/tests/functional/hooks/post_test_hook.sh deleted file mode 100755 index 418523c..0000000 --- a/ironicclient/tests/functional/hooks/post_test_hook.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -xe - -# 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. - -# This script is executed inside post_test_hook function in devstack gate. - -function generate_testr_results { - if [ -f .testrepository/0 ]; then - sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit - sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit - sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html - sudo gzip -9 $BASE/logs/testrepository.subunit - sudo gzip -9 $BASE/logs/testr_results.html - sudo chown jenkins:jenkins $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz - sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz - fi -} - -export IRONICCLIENT_DIR="$BASE/new/python-ironicclient" - -sudo chown -R jenkins:stack $IRONICCLIENT_DIR - -cd $IRONICCLIENT_DIR - -# Run tests -echo "Running ironicclient functional test suite" -set +e - -# Only admin credentials needed for ironic api -source $BASE/new/devstack/openrc admin admin - -# Preserve env for OS_ credentials -sudo -E -H -u jenkins ./tools/run_functional.sh -EXIT_CODE=$? -set -e - -# Collect and parse result -generate_testr_results -exit $EXIT_CODE diff --git a/ironicclient/tests/functional/osc/__init__.py b/ironicclient/tests/functional/osc/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/functional/osc/v1/__init__.py b/ironicclient/tests/functional/osc/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/functional/osc/v1/base.py b/ironicclient/tests/functional/osc/v1/base.py deleted file mode 100644 index b2a3ec9..0000000 --- a/ironicclient/tests/functional/osc/v1/base.py +++ /dev/null @@ -1,286 +0,0 @@ -# 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 - -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions - -from ironicclient.tests.functional import base - - -class TestCase(base.FunctionalTestBase): - - def openstack(self, *args, **kwargs): - return self._ironic_osc(*args, **kwargs) - - def get_opts(self, fields=None, output_format='json'): - """Get options for OSC output fields format. - - :param List fields: List of fields to get - :param String output_format: Select output format - :return: String of formatted options - """ - if not fields: - return ' -f {0}'.format(output_format) - return ' -f {0} {1}'.format(output_format, - ' '.join(['-c ' + it for it in fields])) - - @staticmethod - def construct_cmd(*parts): - return ' '.join(str(x) for x in parts) - - def node_create(self, driver='fake', name=None, params=''): - """Create baremetal node and add cleanup. - - :param String driver: Driver for a new node - :param String name: Name for a new node - :param String params: Additional args and kwargs - :return: JSON object of created node - """ - if not name: - name = data_utils.rand_name('baremetal') - - opts = self.get_opts() - output = self.openstack('baremetal node create {0} ' - '--driver {1} --name {2} {3}' - .format(opts, driver, name, params)) - node = json.loads(output) - self.addCleanup(self.node_delete, node['uuid'], True) - if not output: - self.fail('Baremetal node has not been created!') - - return node - - def node_list(self, fields=None, params=''): - """List baremetal nodes. - - :param List fields: List of fields to show - :param String params: Additional kwargs - :return: list of JSON node objects - """ - opts = self.get_opts(fields=fields) - output = self.openstack('baremetal node list {0} {1}' - .format(opts, params)) - return json.loads(output) - - def node_show(self, identifier, fields=None, params=''): - """Show specified baremetal node. - - :param String identifier: Name or UUID of the node - :param List fields: List of fields to show - :param List params: Additional kwargs - :return: JSON object of node - """ - opts = self.get_opts(fields) - output = self.openstack('baremetal node show {0} {1} {2}' - .format(opts, identifier, params)) - return json.loads(output) - - def node_delete(self, identifier, ignore_exceptions=False): - """Try to delete baremetal node by name or UUID. - - :param String identifier: Name or UUID of the node - :param Bool ignore_exceptions: Ignore exception (needed for cleanUp) - :return: raw values output - :raise: CommandFailed exception when command fails to delete a node - """ - try: - return self.openstack('baremetal node delete {0}' - .format(identifier)) - except exceptions.CommandFailed: - if not ignore_exceptions: - raise - - def port_create(self, node_id, mac_address=None, params=''): - """Create baremetal port and add cleanup. - - :param String node_id: baremetal node UUID - :param String mac_address: MAC address for port - :param String params: Additional args and kwargs - :return: JSON object of created port - """ - if not mac_address: - mac_address = data_utils.rand_mac_address() - - opts = self.get_opts() - port = self.openstack('baremetal port create {0} ' - '--node {1} {2} {3}' - .format(opts, node_id, mac_address, params)) - port = json.loads(port) - if not port: - self.fail('Baremetal port has not been created!') - self.addCleanup(self.port_delete, port['uuid'], True) - return port - - def port_list(self, fields=None, params=''): - """List baremetal ports. - - :param List fields: List of fields to show - :param String params: Additional kwargs - :return: list of JSON port objects - """ - opts = self.get_opts(fields=fields) - output = self.openstack('baremetal port list {0} {1}' - .format(opts, params)) - return json.loads(output) - - def port_show(self, uuid, fields=None, params=''): - """Show specified baremetal port. - - :param String uuid: UUID of the port - :param List fields: List of fields to show - :param List params: Additional kwargs - :return: JSON object of port - """ - opts = self.get_opts(fields) - output = self.openstack('baremetal port show {0} {1} {2}' - .format(opts, uuid, params)) - return json.loads(output) - - def port_delete(self, uuid, ignore_exceptions=False): - """Try to delete baremetal port by UUID. - - :param String uuid: UUID of the port - :param Bool ignore_exceptions: Ignore exception (needed for cleanUp) - :return: raw values output - :raise: CommandFailed exception when command fails to delete a port - """ - try: - return self.openstack('baremetal port delete {0}' - .format(uuid)) - except exceptions.CommandFailed: - if not ignore_exceptions: - raise - - def port_group_list(self, fields=None, params=''): - """List baremetal port groups. - - :param List fields: List of fields to show - :param String params: Additional kwargs - :return: JSON object of port group list - """ - opts = self.get_opts(fields=fields) - output = self.openstack('baremetal port group list {0} {1}' - .format(opts, params)) - return json.loads(output) - - def port_group_create(self, node_id, name=None, params=''): - """Create baremetal port group. - - :param String node_id: baremetal node UUID - :param String name: port group name - :param String params: Additional args and kwargs - :return: JSON object of created port group - """ - if not name: - name = data_utils.rand_name('port_group') - - opts = self.get_opts() - output = self.openstack( - 'baremetal port group create {0} --node {1} --name {2} {3}' - .format(opts, node_id, name, params)) - - port_group = json.loads(output) - if not port_group: - self.fail('Baremetal port group has not been created!') - - self.addCleanup(self.port_group_delete, port_group['uuid'], - params=params, ignore_exceptions=True) - return port_group - - def port_group_delete(self, identifier, params='', - ignore_exceptions=False): - """Try to delete baremetal port group by Name or UUID. - - :param String identifier: Name or UUID of the port group - :param String params: temporary arg to pass api version. - :param Bool ignore_exceptions: Ignore exception (needed for cleanUp) - :return: raw values output - :raise: CommandFailed exception if not ignore_exceptions - """ - try: - return self.openstack('baremetal port group delete {0} {1}' - .format(identifier, params)) - except exceptions.CommandFailed: - if not ignore_exceptions: - raise - - def port_group_show(self, identifier, fields=None, params=''): - """Show specified baremetal port group. - - :param String identifier: Name or UUID of the port group - :param List fields: List of fields to show - :param List params: Additional kwargs - :return: JSON object of port group - """ - opts = self.get_opts(fields) - output = self.openstack('baremetal port group show {0} {1} {2}' - .format(identifier, opts, params)) - return json.loads(output) - - def chassis_create(self, params=''): - """Create baremetal chassis and add cleanup. - - :param String params: Additional args and kwargs - :return: JSON object of created chassis - """ - opts = self.get_opts() - chassis = self.openstack('baremetal chassis create {0} {1}' - .format(opts, params)) - - chassis = json.loads(chassis) - if not chassis: - self.fail('Baremetal chassis has not been created!') - self.addCleanup(self.chassis_delete, chassis['uuid'], True) - - return chassis - - def chassis_delete(self, uuid, ignore_exceptions=False): - """Try to delete baremetal chassis by UUID. - - :param String uuid: UUID of the chassis - :param Bool ignore_exceptions: Ignore exception (needed for cleanUp) - :return: raw values output - :raise: CommandFailed exception when command fails to delete a chassis - """ - try: - return self.openstack('baremetal chassis delete {0}' - .format(uuid)) - except exceptions.CommandFailed: - if not ignore_exceptions: - raise - - def chassis_list(self, fields=None, params=''): - """List baremetal chassis. - - :param List fields: List of fields to show - :param String params: Additional kwargs - :return: list of JSON chassis objects - """ - opts = self.get_opts(fields=fields) - output = self.openstack('baremetal chassis list {0} {1}' - .format(opts, params)) - return json.loads(output) - - def chassis_show(self, uuid, fields=None, params=''): - """Show specified baremetal chassis. - - :param String uuid: UUID of the chassis - :param List fields: List of fields to show - :param List params: Additional kwargs - :return: JSON object of chassis - """ - opts = self.get_opts(fields) - chassis = self.openstack('baremetal chassis show {0} {1} {2}' - .format(opts, uuid, params)) - return json.loads(chassis) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_chassis_basic.py b/ironicclient/tests/functional/osc/v1/test_baremetal_chassis_basic.py deleted file mode 100644 index 140fe5f..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_chassis_basic.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ironicclient.tests.functional.osc.v1 import base - - -class BaremetalChassisTests(base.TestCase): - """Functional tests for baremetal chassis commands.""" - - def setUp(self): - super(BaremetalChassisTests, self).setUp() - self.chassis = self.chassis_create() - - def test_list(self): - """Check baremetal chassis list command. - - Test steps: - 1) Create baremetal chassis in setUp. - 2) List baremetal chassis. - 3) Check chassis description and UUID in chassis list. - """ - chassis_list = self.chassis_list() - self.assertIn(self.chassis['uuid'], - [x['UUID'] for x in chassis_list]) - self.assertIn(self.chassis['description'], - [x['Description'] for x in chassis_list]) - - def test_show(self): - """Check baremetal chassis show command. - - Test steps: - 1) Create baremetal chassis in setUp. - 2) Show baremetal chassis. - 3) Check chassis in chassis show. - """ - chassis = self.chassis_show(self.chassis['uuid']) - self.assertEqual(self.chassis['uuid'], chassis['uuid']) - self.assertEqual(self.chassis['description'], chassis['description']) - - def test_delete(self): - """Check baremetal chassis delete command. - - Test steps: - 1) Create baremetal chassis in setUp. - 2) Delete baremetal chassis by UUID. - 3) Check that chassis deleted successfully. - """ - output = self.chassis_delete(self.chassis['uuid']) - self.assertIn('Deleted chassis {0}'.format(self.chassis['uuid']), - output) - self.assertNotIn(self.chassis['uuid'], self.chassis_list(['UUID'])) - - def test_set_unset_extra(self): - """Check baremetal chassis set and unset commands. - - Test steps: - 1) Create baremetal chassis in setUp. - 2) Set extra data for chassis. - 3) Check that baremetal chassis extra data was set. - 4) Unset extra data for chassis. - 5) Check that baremetal chassis extra data was unset. - """ - extra_key = 'ext' - extra_value = 'testdata' - self.openstack('baremetal chassis set --extra {0}={1} {2}' - .format(extra_key, extra_value, self.chassis['uuid'])) - - show_prop = self.chassis_show(self.chassis['uuid'], ['extra']) - self.assertEqual(extra_value, show_prop['extra'][extra_key]) - - self.openstack('baremetal chassis unset --extra {0} {1}' - .format(extra_key, self.chassis['uuid'])) - - show_prop = self.chassis_show(self.chassis['uuid'], ['extra']) - self.assertNotIn(extra_key, show_prop['extra']) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_node_basic.py b/ironicclient/tests/functional/osc/v1/test_baremetal_node_basic.py deleted file mode 100644 index c968f7e..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_node_basic.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ddt -from tempest.lib.common.utils import data_utils - -from ironicclient.tests.functional.osc.v1 import base - - -@ddt.ddt -class BaremetalNodeTests(base.TestCase): - """Functional tests for baremetal node commands.""" - - def setUp(self): - super(BaremetalNodeTests, self).setUp() - self.node = self.node_create() - - def test_warning_version_not_specified(self): - """Test API version warning is printed when API version unspecified. - - A warning will appear for any invocation of the baremetal OSC plugin - without --os-baremetal-api-version specified. It's tested with a simple - node list command here. - """ - output = self.openstack('baremetal node list', merge_stderr=True) - self.assertIn('the default will be the latest API version', output) - - def test_no_warning_version_specified(self): - """Test API version warning is not printed when API version specified. - - This warning should not appear when a user specifies the ironic API - version to use. - """ - output = self.openstack('baremetal --os-baremetal-api-version=1.9 node' - ' list', merge_stderr=True) - self.assertNotIn('the default will be the latest API version', output) - - def test_create_name_uuid(self): - """Check baremetal node create command with name and UUID. - - Test steps: - 1) Create baremetal node in setUp. - 2) Create one more baremetal node explicitly - with specified name and UUID. - 3) Check that node successfully created. - """ - uuid = data_utils.rand_uuid() - name = data_utils.rand_name('baremetal-node') - node_info = self.node_create(name=name, - params='--uuid {0}'.format(uuid)) - self.assertEqual(node_info['uuid'], uuid) - self.assertEqual(node_info['name'], name) - self.assertEqual(node_info['driver'], 'fake') - self.assertEqual(node_info['maintenance'], False) - node_list = self.node_list() - self.assertIn(uuid, [x['UUID'] for x in node_list]) - self.assertIn(name, [x['Name'] for x in node_list]) - - @ddt.data('name', 'uuid') - def test_delete(self, key): - """Check baremetal node delete command with name/UUID argument. - - Test steps: - 1) Create baremetal node in setUp. - 2) Delete baremetal node by name/UUID. - 3) Check that node deleted successfully. - """ - output = self.node_delete(self.node[key]) - self.assertIn('Deleted node {0}'.format(self.node[key]), output) - node_list = self.node_list() - self.assertNotIn(self.node['name'], [x['Name'] for x in node_list]) - self.assertNotIn(self.node['uuid'], [x['UUID'] for x in node_list]) - - def test_list(self): - """Check baremetal node list command. - - Test steps: - 1) Create baremetal node in setUp. - 2) List baremetal nodes. - 3) Check node name in nodes list. - """ - node_list = self.node_list() - self.assertIn(self.node['name'], [x['Name'] for x in node_list]) - self.assertIn(self.node['uuid'], [x['UUID'] for x in node_list]) - - @ddt.data('name', 'uuid') - def test_set(self, key): - """Check baremetal node set command calling it by name/UUID. - - Test steps: - 1) Create baremetal node in setUp. - 2) Set another name for node calling it by name/UUID. - 3) Check that baremetal node name was changed. - """ - new_name = data_utils.rand_name('newnodename') - self.openstack('baremetal node set --name {0} {1}' - .format(new_name, self.node[key])) - show_prop = self.node_show(self.node['uuid'], ['name']) - self.assertEqual(new_name, show_prop['name']) - - @ddt.data('name', 'uuid') - def test_unset(self, key): - """Check baremetal node unset command calling it by node name/UUID. - - Test steps: - 1) Create baremetal node in setUp. - 2) Unset name of baremetal node calling it by node name/UUID. - 3) Check that node has no more name. - """ - self.openstack('baremetal node unset --name {0}' - .format(self.node[key])) - show_prop = self.node_show(self.node['uuid'], ['name']) - self.assertIsNone(show_prop['name']) - - @ddt.data('name', 'uuid') - def test_show(self, key): - """Check baremetal node show command with name and UUID arguments. - - Test steps: - 1) Create baremetal node in setUp. - 2) Show baremetal node calling it with name and UUID arguments. - 3) Check name, uuid and driver in node show output. - """ - node = self.node_show(self.node[key], - ['name', 'uuid', 'driver']) - self.assertEqual(self.node['name'], node['name']) - self.assertEqual(self.node['uuid'], node['uuid']) - self.assertEqual(self.node['driver'], node['driver']) - - def test_baremetal_node_maintenance_set_unset(self): - """Check baremetal node maintenance set command. - - Test steps: - 1) Create baremetal node in setUp. - 2) Check maintenance status of fresh node is False. - 3) Set maintenance status for node. - 4) Check maintenance status of node is True. - 5) Unset maintenance status for node. - 6) Check maintenance status of node is False back. - """ - show_prop = self.node_show(self.node['name'], ['maintenance']) - self.assertFalse(show_prop['maintenance']) - - self.openstack('baremetal node maintenance set {0}'. - format(self.node['name'])) - - show_prop = self.node_show(self.node['name'], ['maintenance']) - self.assertTrue(show_prop['maintenance']) - - self.openstack('baremetal node maintenance unset {0}'. - format(self.node['name'])) - - show_prop = self.node_show(self.node['name'], ['maintenance']) - self.assertFalse(show_prop['maintenance']) - - def test_baremetal_node_maintenance_set_unset_reason(self): - """Check baremetal node maintenance set command. - - Test steps: - 1) Create baremetal node in setUp. - 2) Check initial maintenance reason is None. - 3) Set maintenance status for node with reason. - 4) Check maintenance reason of node equals to expected value. - Also check maintenance status. - 5) Unset maintenance status for node. Recheck maintenance status. - 6) Check maintenance reason is None. Recheck maintenance status. - """ - reason = "Hardware maintenance." - show_prop = self.node_show(self.node['name'], - ['maintenance_reason', 'maintenance']) - self.assertIsNone(show_prop['maintenance_reason']) - self.assertFalse(show_prop['maintenance']) - - self.openstack("baremetal node maintenance set --reason '{0}' {1}". - format(reason, self.node['name'])) - - show_prop = self.node_show(self.node['name'], - ['maintenance_reason', 'maintenance']) - self.assertEqual(reason, show_prop['maintenance_reason']) - self.assertTrue(show_prop['maintenance']) - - self.openstack('baremetal node maintenance unset {0}'. - format(self.node['name'])) - - show_prop = self.node_show(self.node['name'], - ['maintenance_reason', 'maintenance']) - self.assertIsNone(show_prop['maintenance_reason']) - self.assertFalse(show_prop['maintenance']) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_node_create_negative.py b/ironicclient/tests/functional/osc/v1/test_baremetal_node_create_negative.py deleted file mode 100644 index 05a7803..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_node_create_negative.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ddt -import six -from tempest.lib import exceptions - -from ironicclient.tests.functional.osc.v1 import base - - -@ddt.ddt -class BaremetalNodeCreateNegativeTests(base.TestCase): - """Negative tests for node create command.""" - - def setUp(self): - super(BaremetalNodeCreateNegativeTests, self).setUp() - - @ddt.data( - ('--uuid', '', 'expected one argument'), - ('--uuid', '!@#$^*&%^', 'Expected a UUID'), - ('--uuid', '0000 0000', 'unrecognized arguments'), - ('--driver-info', '', 'expected one argument'), - ('--driver-info', 'some info', 'unrecognized arguments'), - ('--property', '', 'expected one argument'), - ('--property', 'some property', 'unrecognized arguments'), - ('--extra', '', 'expected one argument'), - ('--extra', 'some extra', 'unrecognized arguments'), - ('--name', '', 'expected one argument'), - ('--name', 'some name', 'unrecognized arguments'), - ('--network-interface', '', 'expected one argument'), - ('--resource-class', '', 'expected one argument')) - @ddt.unpack - def test_baremetal_node_create(self, argument, value, ex_text): - base_cmd = 'baremetal node create --driver fake' - command = self.construct_cmd(base_cmd, argument, value) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_node_fields.py b/ironicclient/tests/functional/osc/v1/test_baremetal_node_fields.py deleted file mode 100644 index 79f3a2d..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_node_fields.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (c) 2017 Mirantis, Inc. -# -# 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 six -from tempest.lib import exceptions - -from ironicclient.tests.functional.osc.v1 import base - - -class TestNodeListFields(base.TestCase): - """Functional tests for "baremetal node list" with --fields.""" - - def setUp(self): - super(TestNodeListFields, self).setUp() - self.node = self.node_create() - - def _get_table_headers(self, raw_output): - table = self.parser.table(raw_output) - return table['headers'] - - def test_list_default_fields(self): - """Test presence of default list table headers.""" - headers = ['UUID', 'Name', 'Instance UUID', - 'Power State', 'Provisioning State', 'Maintenance'] - - nodes_list = self.openstack('baremetal node list') - nodes_list_headers = self._get_table_headers(nodes_list) - - self.assertEqual(set(headers), set(nodes_list_headers)) - - def test_list_minimal_fields(self): - headers = ['Instance UUID', 'Name', 'UUID'] - fields = ['instance_uuid', 'name', 'uuid'] - - node_list = self.openstack( - 'baremetal node list --fields {}' - .format(' '.join(fields))) - - nodes_list_headers = self._get_table_headers(node_list) - self.assertEqual(headers, nodes_list_headers) - - def test_list_no_fields(self): - command = 'baremetal node list --fields' - ex_text = 'expected at least one argument' - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) - - def test_list_wrong_field(self): - command = 'baremetal node list --fields ABC' - ex_text = 'invalid choice' - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) - - -class TestNodeShowFields(base.TestCase): - """Functional tests for "baremetal node show" with --fields.""" - - def setUp(self): - super(TestNodeShowFields, self).setUp() - self.node = self.node_create() - self.api_version = '--os-baremetal-api-version 1.20' - - def _get_table_rows(self, raw_output): - table = self.parser.table(raw_output) - rows = [] - for row in table['values']: - rows.append(row[0]) - return rows - - def test_show_default_fields(self): - rows = ['console_enabled', - 'clean_step', - 'created_at', - 'driver', - 'driver_info', - 'driver_internal_info', - 'extra', - 'inspection_finished_at', - 'inspection_started_at', - 'instance_info', - 'instance_uuid', - 'last_error', - 'maintenance', - 'maintenance_reason', - 'name', - 'power_state', - 'properties', - 'provision_state', - 'provision_updated_at', - 'reservation', - 'target_power_state', - 'target_provision_state', - 'updated_at', - 'uuid'] - node_show = self.openstack('baremetal node show {}' - .format(self.node['uuid'])) - nodes_show_rows = self._get_table_rows(node_show) - - self.assertTrue(set(rows).issubset(set(nodes_show_rows))) - - def test_show_minimal_fields(self): - rows = [ - 'instance_uuid', - 'name', - 'uuid'] - - node_show = self.openstack( - 'baremetal node show {} --fields {} {}' - .format(self.node['uuid'], ' '.join(rows), self.api_version)) - - nodes_show_rows = self._get_table_rows(node_show) - self.assertEqual(set(rows), set(nodes_show_rows)) - - def test_show_no_fields(self): - command = 'baremetal node show {} --fields {}'.format( - self.node['uuid'], self.api_version) - ex_text = 'expected at least one argument' - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) - - def test_show_wrong_field(self): - command = 'baremetal node show {} --fields ABC {}'.format( - self.node['uuid'], self.api_version) - ex_text = 'invalid choice' - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_node_negative.py b/ironicclient/tests/functional/osc/v1/test_baremetal_node_negative.py deleted file mode 100644 index c4af874..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_node_negative.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2017 Mirantis, Inc. -# -# 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 ddt -import six -from tempest.lib import exceptions - -from ironicclient.tests.functional.osc.v1 import base - - -@ddt.ddt -class BaremetalNodeNegativeTests(base.TestCase): - """Negative tests for baremetal node commands.""" - - def setUp(self): - super(BaremetalNodeNegativeTests, self).setUp() - self.node = self.node_create() - - @ddt.data( - ('', '', 'error: argument --driver is required'), - ('--driver', 'wrongdriver', - 'No valid host was found. Reason: No conductor service ' - 'registered which supports driver wrongdriver.') - ) - @ddt.unpack - def test_create_driver(self, argument, value, ex_text): - """Negative test for baremetal node driver options.""" - base_cmd = 'baremetal node create' - command = self.construct_cmd(base_cmd, argument, value) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) - - def test_delete_no_node(self): - """Test for baremetal node delete without node specified.""" - command = 'baremetal node delete' - ex_text = 'error: too few arguments' - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) - - def test_list_wrong_argument(self): - """Test for baremetal node list with wrong argument.""" - command = 'baremetal node list --wrong_arg' - ex_text = 'error: unrecognized arguments: --wrong_arg' - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) - - @ddt.data( - ('--property', '', 'error: too few arguments'), - ('--property', 'prop', 'Attributes must be a list of PATH=VALUE') - ) - @ddt.unpack - def test_set_property(self, argument, value, ex_text): - """Negative test for baremetal node set command options.""" - base_cmd = 'baremetal node set' - command = self.construct_cmd(base_cmd, argument, value, - self.node['uuid']) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) - - @ddt.data( - ('--property', '', 'error: too few arguments'), - ('--property', 'prop', "Reason: can't remove non-existent object") - ) - @ddt.unpack - def test_unset_property(self, argument, value, ex_text): - """Negative test for baremetal node unset command options.""" - base_cmd = 'baremetal node unset' - command = self.construct_cmd(base_cmd, argument, value, - self.node['uuid']) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.openstack, command) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_node_power_states.py b/ironicclient/tests/functional/osc/v1/test_baremetal_node_power_states.py deleted file mode 100644 index 24cddd8..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_node_power_states.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ironicclient.tests.functional.osc.v1 import base - - -class PowerStateTests(base.TestCase): - """Functional tests for baremetal node power state commands.""" - - def setUp(self): - super(PowerStateTests, self).setUp() - self.node = self.node_create() - - def test_off_reboot_on(self): - """Reboot node from Power OFF state. - - Test steps: - 1) Create baremetal node in setUp. - 2) Set node Power State OFF as precondition. - 3) Call reboot command for baremetal node. - 4) Check node Power State ON in node properties. - """ - self.openstack('baremetal node power off {0}' - .format(self.node['uuid'])) - show_prop = self.node_show(self.node['uuid'], ['power_state']) - self.assertEqual('power off', show_prop['power_state']) - - self.openstack('baremetal node reboot {0}'.format(self.node['uuid'])) - show_prop = self.node_show(self.node['uuid'], ['power_state']) - self.assertEqual('power on', show_prop['power_state']) - - def test_on_reboot_on(self): - """Reboot node from Power ON state. - - Test steps: - 1) Create baremetal node in setUp. - 2) Set node Power State ON as precondition. - 3) Call reboot command for baremetal node. - 4) Check node Power State ON in node properties. - """ - self.openstack('baremetal node power on {0}'.format(self.node['uuid'])) - show_prop = self.node_show(self.node['uuid'], ['power_state']) - self.assertEqual('power on', show_prop['power_state']) - - self.openstack('baremetal node reboot {0}'.format(self.node['uuid'])) - show_prop = self.node_show(self.node['uuid'], ['power_state']) - self.assertEqual('power on', show_prop['power_state']) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_node_provision_states.py b/ironicclient/tests/functional/osc/v1/test_baremetal_node_provision_states.py deleted file mode 100644 index acc24a2..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_node_provision_states.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ironicclient.tests.functional.osc.v1 import base - - -class ProvisionStateTests(base.TestCase): - """Functional tests for baremetal node provision state commands.""" - - def setUp(self): - super(ProvisionStateTests, self).setUp() - self.node = self.node_create() - - def test_deploy_rebuild_undeploy(self): - """Deploy, rebuild and undeploy node. - - Test steps: - 1) Create baremetal node in setUp. - 2) Check initial "available" provision state. - 3) Set baremetal node "deploy" provision state. - 4) Check baremetal node provision_state field value is "active". - 5) Set baremetal node "rebuild" provision state. - 6) Check baremetal node provision_state field value is "active". - 7) Set baremetal node "undeploy" provision state. - 8) Check baremetal node provision_state field value is "available". - """ - show_prop = self.node_show(self.node['uuid'], ["provision_state"]) - self.assertEqual("available", show_prop["provision_state"]) - - # deploy - self.openstack('baremetal node deploy {0}'.format(self.node['uuid'])) - show_prop = self.node_show(self.node['uuid'], ["provision_state"]) - self.assertEqual("active", show_prop["provision_state"]) - - # rebuild - self.openstack('baremetal node rebuild {0}'.format(self.node['uuid'])) - - show_prop = self.node_show(self.node['uuid'], ["provision_state"]) - self.assertEqual("active", show_prop["provision_state"]) - - # undeploy - self.openstack('baremetal node undeploy {0}'.format(self.node['uuid'])) - - show_prop = self.node_show(self.node['uuid'], ["provision_state"]) - self.assertEqual("available", show_prop["provision_state"]) - - def test_manage_provide(self): - """Manage and provide node back. - - Steps: - 1) Create baremetal node in setUp. - 2) Check initial "available" provision state. - 3) Set baremetal node "manage" provision state. - 4) Check baremetal node provision_state field value is "manageable". - 5) Set baremetal node "provide" provision state. - 6) Check baremetal node provision_state field value is "available". - """ - - show_prop = self.node_show(self.node['uuid'], ["provision_state"]) - self.assertEqual("available", show_prop["provision_state"]) - - # manage - self.openstack('baremetal node manage {0}'.format(self.node['uuid'])) - show_prop = self.node_show(self.node['uuid'], ["provision_state"]) - self.assertEqual("manageable", show_prop["provision_state"]) - - # provide back - self.openstack('baremetal node provide {0}'.format(self.node['uuid'])) - show_prop = self.node_show(self.node['uuid'], ["provision_state"]) - self.assertEqual("available", show_prop["provision_state"]) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_port_basic.py b/ironicclient/tests/functional/osc/v1/test_baremetal_port_basic.py deleted file mode 100644 index d4b5fc7..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_port_basic.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ironicclient.tests.functional.osc.v1 import base - - -class BaremetalPortTests(base.TestCase): - """Functional tests for baremetal port commands.""" - - def setUp(self): - super(BaremetalPortTests, self).setUp() - self.node = self.node_create() - self.port = self.port_create(self.node['uuid']) - - def test_list(self): - """Check baremetal port list command. - - Test steps: - 1) Create baremetal port in setUp. - 2) List baremetal ports. - 3) Check port address and UUID in ports list. - """ - port_list = self.port_list() - self.assertIn(self.port['address'], - [port['Address'] for port in port_list]) - self.assertIn(self.port['uuid'], - [port['UUID'] for port in port_list]) - - def test_show_uuid(self): - """Check baremetal port show command with UUID. - - Test steps: - 1) Create baremetal port in setUp. - 2) Show baremetal port calling it by UUID. - 3) Check port fields in output. - """ - port = self.port_show(self.port['uuid']) - self.assertEqual(self.port['address'], port['address']) - self.assertEqual(self.port['uuid'], port['uuid']) - self.assertEqual(self.port['node_uuid'], self.node['uuid']) - - def test_show_addr(self): - """Check baremetal port show command with address. - - Test steps: - 1) Create baremetal port in setUp. - 2) Show baremetal port calling it by address. - 3) Check port fields in output. - """ - port = self.port_show( - uuid='', params='--address {}'.format(self.port['address'])) - self.assertEqual(self.port['address'], port['address']) - self.assertEqual(self.port['uuid'], port['uuid']) - self.assertEqual(self.port['node_uuid'], self.node['uuid']) - - def test_delete(self): - """Check baremetal port delete command. - - Test steps: - 1) Create baremetal port in setUp. - 2) Delete baremetal port by UUID. - 3) Check that port deleted successfully and not in list. - """ - output = self.port_delete(self.port['uuid']) - self.assertIn('Deleted port {0}'.format(self.port['uuid']), output) - port_list = self.port_list() - self.assertNotIn(self.port['address'], - [port['Address'] for port in port_list]) - self.assertNotIn(self.port['uuid'], - [port['UUID'] for port in port_list]) - - def test_set_unset_extra(self): - """Check baremetal port set and unset commands. - - Test steps: - 1) Create baremetal port in setUp. - 2) Set extra data for port. - 3) Check that baremetal port extra data was set. - 4) Unset extra data for port. - 5) Check that baremetal port extra data was unset. - """ - extra_key = 'ext' - extra_value = 'testdata' - self.openstack('baremetal port set --extra {0}={1} {2}' - .format(extra_key, extra_value, self.port['uuid'])) - - show_prop = self.port_show(self.port['uuid'], ['extra']) - self.assertEqual(extra_value, show_prop['extra'][extra_key]) - - self.openstack('baremetal port unset --extra {0} {1}' - .format(extra_key, self.port['uuid'])) - - show_prop = self.port_show(self.port['uuid'], ['extra']) - self.assertNotIn(extra_key, show_prop['extra']) diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_portgroup_basic.py b/ironicclient/tests/functional/osc/v1/test_baremetal_portgroup_basic.py deleted file mode 100644 index ee5b5a5..0000000 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_portgroup_basic.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ddt - -from tempest.lib.common.utils import data_utils - -from ironicclient.tests.functional.osc.v1 import base - - -@ddt.ddt -class BaremetalPortGroupTests(base.TestCase): - """Functional tests for baremetal port group commands.""" - - def setUp(self): - super(BaremetalPortGroupTests, self).setUp() - self.node = self.node_create() - self.api_version = ' --os-baremetal-api-version 1.25' - self.port_group = self.port_group_create(self.node['uuid'], - params=self.api_version) - - def test_create_with_address(self): - """Check baremetal port group create command with address argument. - - Test steps: - 1) Create baremetal port group in setUp. - 2) Create baremetal port group with specific address argument. - 3) Check address of created port group. - """ - mac_address = data_utils.rand_mac_address() - port_group = self.port_group_create( - self.node['uuid'], - params='{0} --address {1}'.format(self.api_version, mac_address)) - self.assertEqual(mac_address, port_group['address']) - - def test_list(self): - """Check baremetal port group list command. - - Test steps: - 1) Create baremetal port group in setUp. - 2) List baremetal port groups. - 3) Check port group address, UUID and name in port groups list. - """ - port_group_list = self.port_group_list(params=self.api_version) - - self.assertIn(self.port_group['uuid'], - [x['UUID'] for x in port_group_list]) - self.assertIn(self.port_group['name'], - [x['Name'] for x in port_group_list]) - - @ddt.data('name', 'uuid') - def test_delete(self, key): - """Check baremetal port group delete command. - - Test steps: - 1) Create baremetal port group in setUp. - 2) Delete baremetal port group by UUID. - 3) Check that port group deleted successfully and not in list. - """ - output = self.port_group_delete(self.port_group[key], - params=self.api_version) - self.assertEqual('Deleted port group {0}' - .format(self.port_group[key]), output.strip()) - - port_group_list = self.port_group_list(params=self.api_version) - - self.assertNotIn(self.port_group['uuid'], - [x['UUID'] for x in port_group_list]) - self.assertNotIn(self.port_group['name'], - [x['Name'] for x in port_group_list]) - - @ddt.data('name', 'uuid') - def test_show(self, key): - """Check baremetal port group show command. - - Test steps: - 1) Create baremetal port group in setUp. - 2) Show baremetal port group. - 3) Check name, uuid and address in port group show output. - """ - port_group = self.port_group_show( - self.port_group[key], - ['name', 'uuid', 'address'], - params=self.api_version) - - self.assertEqual(self.port_group['name'], port_group['name']) - self.assertEqual(self.port_group['uuid'], port_group['uuid']) - self.assertEqual(self.port_group['address'], port_group['address']) - - @ddt.data('name', 'uuid') - def test_set_unset(self, key): - """Check baremetal port group set and unset commands. - - Test steps: - 1) Create baremetal port group in setUp. - 2) Set extra data for port group. - 3) Check that baremetal port group extra data was set. - 4) Unset extra data for port group. - 5) Check that baremetal port group extra data was unset. - """ - extra_key = 'ext' - extra_value = 'testdata' - self.openstack( - 'baremetal port group set --extra {0}={1} {2} {3}' - .format(extra_key, extra_value, self.port_group[key], - self.api_version)) - - show_prop = self.port_group_show(self.port_group[key], ['extra'], - params=self.api_version) - self.assertEqual(extra_value, show_prop['extra'][extra_key]) - - self.openstack('baremetal port group unset --extra {0} {1} {2}' - .format(extra_key, self.port_group[key], - self.api_version)) - - show_prop = self.port_group_show(self.port_group[key], ['extra'], - params=self.api_version) - self.assertNotIn(extra_key, show_prop['extra']) diff --git a/ironicclient/tests/functional/test_chassis.py b/ironicclient/tests/functional/test_chassis.py deleted file mode 100644 index 7ac944b..0000000 --- a/ironicclient/tests/functional/test_chassis.py +++ /dev/null @@ -1,213 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 six -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions - -from ironicclient.tests.functional import base - - -class ChassisSanityTestIronicClient(base.FunctionalTestBase): - """Sanity tests for testing actions with Chassis. - - Smoke test for the Ironic CLI commands which checks basic actions with - chassis command like create, show, update, delete etc. - """ - def setUp(self): - super(ChassisSanityTestIronicClient, self).setUp() - self.chassis = self.create_chassis() - - def test_chassis_create(self): - """Test steps: - - 1) create chassis - 2) check that chassis has been successfully created - """ - chassis_list_uuid = self.get_chassis_uuids_from_chassis_list() - self.assertIn(self.chassis['uuid'], chassis_list_uuid) - - def test_chassis_delete(self): - """Test steps: - - 1) create chassis - 2) check that chassis has been successfully created - 3) delete chassis - 4) check that chassis has been successfully deleted - """ - self.delete_chassis(self.chassis['uuid']) - chassis_list_uuid = self.get_chassis_uuids_from_chassis_list() - - self.assertNotIn(self.chassis['uuid'], chassis_list_uuid) - - def test_chassis_show(self): - """Test steps: - - 1) create chassis - 2) check that chassis-show returns the same chassis UUID - 3) chassis-create - """ - chassis_show = self.show_chassis(self.chassis['uuid']) - self.assertEqual(self.chassis['uuid'], chassis_show['uuid']) - - def test_chassis_show_field(self): - """Test steps: - - 1) create chassis - 2) show chassis with fields uuid - 3) check that fields is exist - """ - fields = ['uuid'] - chassis_show = self.show_chassis(self.chassis['uuid'], - params='--fields {0}' - .format(*fields)) - self.assertTableHeaders(fields, chassis_show.keys()) - - def test_chassis_update(self): - """Test steps: - - 1) create chassis - 2) update chassis - 3) check that chassis has been successfully updated - """ - updated_chassis = self.update_chassis( - self.chassis['uuid'], 'add', 'description=test-chassis') - self.assertEqual('test-chassis', updated_chassis['description']) - self.assertNotEqual(self.chassis['description'], - updated_chassis['description']) - - def test_chassis_node_list(self): - """Test steps: - - 1) create chassis in setUp() - 2) create 3 nodes - 3) update 2 nodes to be included in chassis - 4) check if 2 nodes are added to chassis - 5) check if 1 nodes isn't added to chassis - """ - node1 = self.create_node() - node2 = self.create_node() - - # This node is created to show that it won't be present - # in the chassis-node-list output - - node3 = self.create_node() - updated_node1 = self.update_node(node1['uuid'], - 'add chassis_uuid={0}' - .format(self.chassis['uuid'])) - updated_node2 = self.update_node(node2['uuid'], - 'add chassis_uuid={0}' - .format(self.chassis['uuid'])) - nodes = [updated_node1['uuid'], updated_node2['uuid']] - nodes.sort() - nodes_uuids = self.get_nodes_uuids_from_chassis_node_list( - self.chassis['uuid']) - nodes_uuids.sort() - self.assertEqual(nodes, nodes_uuids) - self.assertNotIn(node3['uuid'], nodes_uuids) - - -class ChassisNegativeTestsIronicClient(base.FunctionalTestBase): - """Negative tests for testing actions with Chassis. - - Negative tests for the Ironic CLI commands which checks actions with - chassis command like show, update, delete either using with arguments - or without arguments. - """ - - def test_chassis_delete_without_arguments(self): - """Test step: - - 1) check that chassis-delete command without arguments - triggers an exception - """ - ex_text = r'chassis-delete: error: too few arguments' - - six.assertRaisesRegex(self, exceptions.CommandFailed, - ex_text, - self.delete_chassis, '') - - def test_chassis_delete_with_incorrect_chassis_uuid(self): - """Test step: - - 1) check that deleting non-exist chassis triggers an exception - triggers an exception - """ - uuid = data_utils.rand_uuid() - ex_text = (r"Chassis {0} " - r"could not be found. \(HTTP 404\)".format(uuid)) - - six.assertRaisesRegex(self, exceptions.CommandFailed, - ex_text, - self.delete_chassis, - '{0}'.format(uuid)) - - def test_chassis_show_without_arguments(self): - """Test step: - - 1) check that chassis-show command without arguments - triggers an exception - """ - ex_text = r'chassis-show: error: too few arguments' - - six.assertRaisesRegex(self, exceptions.CommandFailed, - ex_text, - self.show_chassis, '') - - def test_chassis_show_with_incorrect_chassis_uuid(self): - """Test step: - - 1) check that chassis-show command with incorrect chassis - uuid triggers an exception - """ - uuid = data_utils.rand_uuid() - ex_text = (r"Chassis {0} " - r"could not be found. \(HTTP 404\)".format(uuid)) - - six.assertRaisesRegex(self, exceptions.CommandFailed, - ex_text, - self.show_chassis, - '{0}'.format(uuid)) - - def test_chassis_update_without_arguments(self): - """Test steps: - - 1) create chassis - 2) check that chassis-update command without arguments - triggers an exception - """ - ex_text = r'chassis-update: error: too few arguments' - - six.assertRaisesRegex(self, exceptions.CommandFailed, - ex_text, - self.update_chassis, - chassis_id='', - operation='') - - def test_chassis_update_with_incorrect_chassis_uuid(self): - """Test steps: - - 1) create chassis - 2) check that chassis-update command with incorrect arguments - triggers an exception - """ - uuid = data_utils.rand_uuid() - ex_text = r'chassis-update: error: too few arguments' - - six.assertRaisesRegex(self, - exceptions.CommandFailed, - ex_text, - self.update_chassis, - chassis_id='{0}'.format(uuid), - operation='') diff --git a/ironicclient/tests/functional/test_chassis_create.py b/ironicclient/tests/functional/test_chassis_create.py deleted file mode 100644 index 9ac7039..0000000 --- a/ironicclient/tests/functional/test_chassis_create.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 six -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions - -from ironicclient.tests.functional import base - - -class NegativeChassisCreateTestsIronicClient(base.FunctionalTestBase): - """Negative tests for testing chassis-create command. - - Negative tests for the Ironic CLI commands which check actions with - chassis-create command like create chassis without arguments or with - incorrect arguments and check that correct error message raised. - """ - - error_msg = r'ironic chassis-create: error:' - expected_msg = r'expected one argument' - - def test_description_no_value(self): - """Test steps: - - 1) create chassis using -d argument without the value - 2) create chassis using --description argument without the value - 3) check that command using -d argument triggers an exception - 4) check that command with --description arg triggers an exception - """ - ex_text = (r'{0} argument -d/--description: {1}' - .format(self.error_msg, self.expected_msg)) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, '-d') - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, '--description') - - def test_metadata_extra_no_value(self): - """Test steps: - - 1) create chassis using -e argument without the value - 2) create chassis using --extra argument without the value - 3) check that command using -e argument triggers an exception - 4) check that command with --extra argument triggers an exception - """ - ex_text = (r'{0} argument -e/--extra: {1}' - .format(self.error_msg, self.expected_msg)) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, '-e') - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, '--extra') - - def test_specific_uuid_no_value(self): - """Test steps: - - 1) create chassis using -u argument without the value - 2) create chassis using --uuid argument without the value - 3) check that command using -u argument triggers an exception - 4) check that command with --uuid argument triggers an exception - """ - ex_text = (r'{0} argument -u/--uuid: {1}' - .format(self.error_msg, self.expected_msg)) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, '-u') - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, '--uuid') - - def test_invalid_description(self): - """Test steps: - - 1) create chassis with invalid description using -d argument - 2) create chassis with invalid description using --description arg - 3) check that command using -d argument triggers an exception - 4) check that command using --uuid argument triggers an exception - """ - description = '--' - ex_text = (r'{0} argument -d/--description: {1}' - .format(self.error_msg, self.expected_msg)) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, - params='-d {0}'.format(description)) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, - params='--description {0}'.format(description)) - - def test_invalid_metadata_extra(self): - """Test steps: - - 1) create chassis with invalid metadata using -e argument - 2) create chassis with invalid metadata using --extra argument - 3) check that command using -e argument triggers an exception - 4) check that command using --extra argument triggers an exception - """ - extra = "HelloWorld" - ex_text = (r'{0} Attributes must be a list of PATH=VALUE' - .format(self.error_msg)) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, - params='-e {0}'.format(extra)) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, - params='--extra {0}'.format(extra)) - - def test_invalid_specific_uuid(self): - """Test steps: - - 1) create chassis with invalid specific uuid using -u argument - 2) create chassis with invalid specific uuid using --uuid argument - 3) check that command using -u argument triggers an exception - 4) check that command using --uuid argument triggers an exception - """ - invalid_uuid = data_utils.rand_uuid()[:-1] - ex_text = r'Expected a UUID but received {0}'.format(invalid_uuid) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, - params='-u {0}'.format(invalid_uuid)) - six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text, - self.create_chassis, - params='--uuid {0}'.format(invalid_uuid)) diff --git a/ironicclient/tests/functional/test_driver.py b/ironicclient/tests/functional/test_driver.py deleted file mode 100644 index c85bd4c..0000000 --- a/ironicclient/tests/functional/test_driver.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2015 Mirantis, Inc. -# -# 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 ironicclient.tests.functional import base - - -class DriverSanityTestIronicClient(base.FunctionalTestBase): - """Sanity tests for testing actions with driver. - - Smoke test for the Ironic CLI commands which checks basic actions with - driver command like driver-show, driver-properties. - """ - - def test_driver_show(self): - """Test steps: - - 1) get drivers names - 2) check that each driver exists in driver-show output - """ - drivers_names = self.get_drivers_names() - for driver in drivers_names: - driver_show = self.show_driver(driver) - self.assertEqual(driver, driver_show['name']) - - def test_driver_properties(self): - """Test steps: - - 1) get drivers names - 2) check that each driver has some properties - """ - drivers_names = self.get_drivers_names() - for driver in drivers_names: - driver_properties = self.properties_driver(driver) - self.assertNotEqual([], [x['Property'] for x in driver_properties]) - - def test_driver_list(self): - """Test steps: - - 1) get list of drivers - 2) check that list of drivers is not empty - """ - driver = 'fake' - available_drivers = self.get_drivers_names() - self.assertTrue(len(available_drivers) > 0) - self.assertIn(driver, available_drivers) diff --git a/ironicclient/tests/functional/test_help_msg.py b/ironicclient/tests/functional/test_help_msg.py deleted file mode 100644 index 07b094b..0000000 --- a/ironicclient/tests/functional/test_help_msg.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2015 Mirantis, Inc. -# -# 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 ironicclient.tests.functional import base - - -class IronicClientHelp(base.FunctionalTestBase): - """Test for python-ironicclient help messages.""" - - def test_ironic_help(self): - """Check Ironic client main help message contents.""" - caption = ("Command-line interface to the " - "OpenStack Bare Metal Provisioning API.") - subcommands = { - 'bash-completion', - 'chassis-create', - 'chassis-delete', - 'chassis-list', - 'chassis-node-list', - 'chassis-show', - 'chassis-update', - 'driver-list', - 'driver-properties', - 'driver-show', - 'driver-vendor-passthru', - 'help', - 'node-create', - 'node-delete', - 'node-get-boot-device', - 'node-get-console', - 'node-get-supported-boot-devices', - 'node-list', - 'node-port-list', - 'node-set-boot-device', - 'node-set-console-mode', - 'node-set-maintenance', - 'node-set-power-state', - 'node-set-provision-state', - 'node-show', - 'node-show-states', - 'node-update', - 'node-validate', - 'node-vendor-passthru', - 'node-vif-attach', - 'node-vif-detach', - 'node-vif-list', - 'port-create', - 'port-delete', - 'port-list', - 'port-show', - 'port-update' - } - - output = self._ironic('help', flags='', params='') - - self.assertIn(caption, output) - for string in subcommands: - self.assertIn(string, output) - - def test_warning_on_api_version(self): - result = self._ironic('help', merge_stderr=True) - self.assertIn('You are using the default API version', result) - - result = self._ironic('help', flags='--ironic-api-version 1.9', - merge_stderr=True) - self.assertNotIn('You are using the default API version', result) diff --git a/ironicclient/tests/functional/test_json_response.py b/ironicclient/tests/functional/test_json_response.py deleted file mode 100644 index 2aeb2a9..0000000 --- a/ironicclient/tests/functional/test_json_response.py +++ /dev/null @@ -1,287 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 jsonschema -from tempest.lib.common.utils import data_utils - -from ironicclient.tests.functional import base - - -def _is_valid_json(json_response, schema): - """Verify JSON is valid. - - :param json_response: JSON response from CLI - :type json_response: string - :param schema: expected schema of response - :type json_response: dictionary - """ - try: - json_response = json.loads(json_response) - jsonschema.validate(json_response, schema) - except jsonschema.ValidationError: - return False - return True - - -class TestNodeJsonResponse(base.FunctionalTestBase): - """Test JSON responses for node commands.""" - - node_schema = { - "type": "object", - "properties": { - "target_power_state": {"type": ["string", "null"]}, - "extra": {"type": "object"}, - "last_error": {"type": ["string", "null"]}, - "updated_at": {"type": ["string", "null"]}, - "maintenance_reason": {"type": ["string", "null"]}, - "provision_state": {"type": "string"}, - "clean_step": {"type": "object"}, - "uuid": {"type": "string"}, - "console_enabled": {"type": "boolean"}, - "target_provision_state": {"type": ["string", "null"]}, - "raid_config": {"type": "string"}, - "provision_updated_at": {"type": ["string", "null"]}, - "maintenance": {"type": "boolean"}, - "target_raid_config": {"type": "string"}, - "inspection_started_at": {"type": ["string", "null"]}, - "inspection_finished_at": {"type": ["string", "null"]}, - "power_state": {"type": ["string", "null"]}, - "driver": {"type": "string"}, - "reservation": {"type": ["string", "null"]}, - "properties": {"type": "object"}, - "instance_uuid": {"type": ["string", "null"]}, - "name": {"type": ["string", "null"]}, - "driver_info": {"type": "object"}, - "created_at": {"type": "string"}, - "driver_internal_info": {"type": "object"}, - "chassis_uuid": {"type": ["string", "null"]}, - "instance_info": {"type": "object"} - } - } - - def setUp(self): - super(TestNodeJsonResponse, self).setUp() - self.node = self.create_node() - - def test_node_list_json(self): - """Test JSON response for nodes list.""" - schema = { - "type": "array", - "items": { - "type": "object", - "properties": { - "instance_uuid": {"type": ["string", "null"]}, - "maintenance": {"type": "boolean"}, - "name": {"type": ["string", "null"]}, - "power_state": {"type": ["string", "null"]}, - "provision_state": {"type": "string"}, - "uuid": {"type": "string"}}} - } - response = self.ironic('node-list', flags='--json', - params='', parse=False) - self.assertTrue(_is_valid_json(response, schema)) - - def test_node_show_json(self): - """Test JSON response for node show.""" - response = self.ironic('node-show', flags='--json', params='{0}' - .format(self.node['uuid']), parse=False) - self.assertTrue(_is_valid_json(response, self.node_schema)) - - def test_node_validate_json(self): - """Test JSON response for node validation.""" - schema = { - "type": "array", - "items": { - "type": "object", - "properties": { - "interface": {"type": ["string", "null"]}, - "result": {"type": "boolean"}, - "reason": {"type": ["string", "null"]}}} - } - response = self.ironic('node-validate', flags='--json', - params='{0}'.format(self.node['uuid']), - parse=False) - self.assertTrue(_is_valid_json(response, schema)) - - def test_node_show_states_json(self): - """Test JSON response for node show states.""" - schema = { - "type": "object", - "properties": { - "target_power_state": {"type": ["string", "null"]}, - "target_provision_state": {"type": ["string", "null"]}, - "last_error": {"type": ["string", "null"]}, - "console_enabled": {"type": "boolean"}, - "provision_updated_at": {"type": ["string", "null"]}, - "power_state": {"type": ["string", "null"]}, - "provision_state": {"type": "string"} - } - } - response = self.ironic('node-show-states', flags='--json', - params='{0}'.format(self.node['uuid']), - parse=False) - self.assertTrue(_is_valid_json(response, schema)) - - def test_node_create_json(self): - """Test JSON response for node creation.""" - schema = { - "type": "object", - "properties": { - "uuid": {"type": "string"}, - "driver_info": {"type": "object"}, - "extra": {"type": "object"}, - "driver": {"type": "string"}, - "chassis_uuid": {"type": ["string", "null"]}, - "properties": {"type": "object"}, - "name": {"type": ["string", "null"]}, - } - } - node_name = 'nodejson' - response = self.ironic('node-create', flags='--json', - params='-d fake -n {0}'.format(node_name), - parse=False) - self.addCleanup(self.delete_node, node_name) - self.assertTrue(_is_valid_json(response, schema)) - - def test_node_update_json(self): - """Test JSON response for node update.""" - node_name = data_utils.rand_name('test') - response = self.ironic('node-update', flags='--json', - params='{0} add name={1}' - .format(self.node['uuid'], node_name), - parse=False) - self.assertTrue(_is_valid_json(response, self.node_schema)) - - -class TestDriverJsonResponse(base.FunctionalTestBase): - """Test JSON responses for driver commands.""" - - def test_driver_list_json(self): - """Test JSON response for drivers list.""" - schema = { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": {"type": "string"}, - "hosts": {"type": "string"}, - }} - } - response = self.ironic('driver-list', flags='--json', parse=False) - self.assertTrue(_is_valid_json(response, schema)) - - def test_driver_show_json(self): - """Test JSON response for driver show.""" - schema = { - "type": "object", - "properties": { - "name": {"type": "string"}, - "hosts": { - "type": "array", - "items": {"type": "string"}} - } - } - drivers_names = self.get_drivers_names() - for driver in drivers_names: - response = self.ironic('driver-show', flags='--json', - params='{0}'.format(driver), parse=False) - self.assertTrue(_is_valid_json(response, schema)) - - def test_driver_properties_json(self): - """Test JSON response for driver properties.""" - schema = { - "type": "object", - "additionalProperties": {"type": "string"} - } - drivers_names = self.get_drivers_names() - for driver in drivers_names: - response = self.ironic('driver-properties', flags='--json', - params='{0}'.format(driver), parse=False) - self.assertTrue(_is_valid_json(response, schema)) - - -class TestChassisJsonResponse(base.FunctionalTestBase): - """Test JSON responses for chassis commands.""" - - chassis_schema = { - "type": "object", - "properties": { - "uuid": {"type": "string"}, - "updated_at": {"type": ["string", "null"]}, - "created_at": {"type": "string"}, - "description": {"type": ["string", "null"]}, - "extra": {"type": "object"}} - } - - def setUp(self): - super(TestChassisJsonResponse, self).setUp() - self.chassis = self.create_chassis() - - def test_chassis_list_json(self): - """Test JSON response for chassis list.""" - schema = { - "type": "array", - "items": { - "type": "object", - "properties": { - "uuid": {"type": "string"}, - "description": {"type": ["string", "null"]}} - } - } - response = self.ironic('chassis-list', flags='--json', parse=False) - self.assertTrue(_is_valid_json(response, schema)) - - def test_chassis_show_json(self): - """Test JSON response for chassis show.""" - response = self.ironic('chassis-show', flags='--json', - params='{0}'.format(self.chassis['uuid']), - parse=False) - self.assertTrue(_is_valid_json(response, self.chassis_schema)) - - def test_chassis_create_json(self): - """Test JSON response for chassis create.""" - response = self.ironic('chassis-create', flags='--json', parse=False) - self.assertTrue(_is_valid_json(response, self.chassis_schema)) - - def test_chassis_update_json(self): - """Test JSON response for chassis update.""" - response = self.ironic( - 'chassis-update', flags='--json', params='{0} {1} {2}'.format( - self.chassis['uuid'], 'add', 'description=test-chassis'), - parse=False) - self.assertTrue(_is_valid_json(response, self.chassis_schema)) - - def test_chassis_node_list_json(self): - """Test JSON response for chassis-node-list command.""" - schema = { - "type": "array", - "items": { - "type": "object", - "properties": { - "instance_uuid": {"type": ["string", "null"]}, - "maintenance": {"type": "boolean"}, - "name": {"type": ["string", "null"]}, - "power_state": {"type": ["string", "null"]}, - "provision_state": {"type": "string"}, - "uuid": {"type": "string"}}} - } - self.node = self.create_node() - self.update_node(self.node['uuid'], 'add chassis_uuid={0}' - .format(self.chassis['uuid'])) - response = self.ironic('chassis-node-list', flags='--json', - params='{0}'.format(self.chassis['uuid']), - parse=False) - self.assertTrue(_is_valid_json(response, schema)) diff --git a/ironicclient/tests/functional/test_node.py b/ironicclient/tests/functional/test_node.py deleted file mode 100644 index a512b7f..0000000 --- a/ironicclient/tests/functional/test_node.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright (c) 2015 Mirantis, Inc. -# -# 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 tempest.lib.common.utils import data_utils - -from ironicclient.tests.functional import base -import ironicclient.tests.functional.utils as utils - - -class NodeSanityTestIronicClient(base.FunctionalTestBase): - """Sanity tests for testing actions with Node. - - Smoke test for the Ironic CLI commands which checks basic actions with - node command like create, delete etc. - """ - - def setUp(self): - super(NodeSanityTestIronicClient, self).setUp() - self.node = self.create_node() - - def test_node_create(self): - """Test steps: - - 1) create node - 2) check that node has been successfully created - """ - self.assertIn(self.node['uuid'], self.get_nodes_uuids_from_node_list()) - - def test_node_show(self): - """Test steps: - - 1) create node - 2) check that created node UUID equals to the one present - in node-show output - """ - node_show = self.show_node(self.node['uuid']) - self.assertEqual(self.node['uuid'], node_show['uuid']) - - def test_node_show_field(self): - """Test steps: - - 1) create node - 2) show node with fields instance_uuid, driver, name, uuid - 3) check that only fields instance_uuid, driver, name, - uuid are the output fields - """ - fields = ['instance_uuid', 'driver', 'name', 'uuid'] - node_show = self.show_node(self.node['uuid'], - params='--fields %s' % ' '.join(fields)) - self.assertTableHeaders(fields, node_show.keys()) - - def test_node_delete(self): - """Test steps: - - 1) create node - 2) check that it was created - 3) delete node - 4) check that node has been successfully deleted - """ - self.assertIn(self.node['uuid'], self.get_nodes_uuids_from_node_list()) - self.delete_node(self.node['uuid']) - self.assertNotIn(self.node['uuid'], - self.get_nodes_uuids_from_node_list()) - - def test_node_update(self): - """Test steps: - - 1) create node - 2) update node name - 3) check that node name has been successfully updated - """ - node_name = data_utils.rand_name(prefix='test') - updated_node = self.update_node(self.node['uuid'], - 'add name={0}'.format(node_name)) - self.assertEqual(node_name, updated_node['name']) - - def test_node_set_console_mode(self): - """Test steps: - - 1) create node - 2) check that console_enabled is False - 3) set node console mode to True - 4) check that node console mode has been successfully updated - """ - node_show = self.show_node(self.node['uuid']) - - self.assertEqual('False', node_show['console_enabled']) - - self.ironic('node-set-console-mode', - params='{0} true'.format(self.node['uuid'])) - node_show = self.show_node(self.node['uuid']) - - self.assertEqual('True', node_show['console_enabled']) - - def test_node_get_console(self): - """Test steps: - - 1) create node - 2) check console mode using node-show - 3) get console mode using node-get-console - 4) check that node-get-console value equals node-show value - """ - node_show = self.show_node(self.node['uuid']) - node_get = self.ironic('node-get-console', params=self.node['uuid']) - node_get = utils.get_dict_from_output(node_get) - - self.assertEqual(node_show['console_enabled'], - node_get['console_enabled']) - - def test_node_set_maintenance(self): - """Test steps: - - 1) create node - 2) check that maintenance is False - 3) put node to maintenance - 4) check that node is in maintenance - 5) check that maintenance reason has been successfully updated - """ - node_show = self.show_node(self.node['uuid']) - - self.assertEqual('False', node_show['maintenance']) - - self.set_node_maintenance( - self.node['uuid'], - "true --reason 'Testing node-set power state command'") - node_show = self.show_node(self.node['uuid']) - - self.assertEqual('True', node_show['maintenance']) - self.assertEqual('Testing node-set power state command', - node_show['maintenance_reason']) - - def test_node_set_power_state(self): - """Test steps: - - 1) create node - 2) check that power state is None - 3) set power state to 'off' - 4) check that power state has been changed successfully - """ - node_show = self.show_node(self.node['uuid']) - - self.assertEqual('None', node_show['power_state']) - - self.set_node_power_state(self.node['uuid'], "off") - node_show = self.show_node(self.node['uuid']) - - self.assertEqual('power off', node_show['power_state']) - - def test_node_set_provision_state(self): - """Test steps: - - 1) create node - 2) check that provision state is 'available' - 3) set new provision state to the node - 4) check that provision state has been updated successfully - """ - node_show = self.show_node(self.node['uuid']) - - self.assertEqual('available', node_show['provision_state']) - - self.set_node_provision_state(self.node['uuid'], 'active') - node_show = self.show_node(self.node['uuid']) - - self.assertEqual('active', node_show['provision_state']) - - def test_node_validate(self): - """Test steps: - - 1) create node - 2) validate node - """ - node_validate = self.validate_node(self.node['uuid']) - self.assertNodeValidate(node_validate) - - def test_show_node_states(self): - """Test steps: - - 1) create node - 2) check that states returned by node-show and node-show-states - are the same - """ - node_show = self.show_node(self.node['uuid']) - show_node_states = self.show_node_states(self.node['uuid']) - self.assertNodeStates(node_show, show_node_states) - - def test_node_list(self): - """Test steps: - - 1) create node in setup and one more node explicitly - 2) check that both nodes are in list - """ - other_node = self.create_node() - node_list = self.list_nodes() - uuids = [x['UUID'] for x in node_list] - names = [x['Name'] for x in node_list] - self.assertIn(self.node['uuid'], uuids) - self.assertIn(other_node['uuid'], uuids) - self.assertIn(self.node['name'], names) - self.assertIn(other_node['name'], names) diff --git a/ironicclient/tests/functional/test_node_set_power_state.py b/ironicclient/tests/functional/test_node_set_power_state.py deleted file mode 100644 index 634548f..0000000 --- a/ironicclient/tests/functional/test_node_set_power_state.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (c) 2015 Mirantis, Inc. -# -# 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 ironicclient.tests.functional import base - - -class NodeSetPowerStateTestIronicClient(base.FunctionalTestBase): - """Tests for testing node-set-power-state command. - - Tests for the Ironic CLI node-set-power-state command that checks that - node can be set to 'on', 'off' or 'reboot' power states - """ - - def setUp(self): - super(NodeSetPowerStateTestIronicClient, self).setUp() - self.node = self.create_node() - node_power_state = self.show_node_states(self.node['uuid']) - self.assertEqual('None', node_power_state['power_state']) - - def test_node_set_power_state_on(self): - """Test steps: - - 1) create node - 2) set node power state to 'on' - 3) check node power state has been set to 'on' - """ - self.set_node_power_state(self.node['uuid'], 'on') - node_state = self.show_node_states(self.node['uuid']) - self.assertEqual('power on', node_state['power_state']) - - def test_node_set_power_state_off(self): - """Test steps: - - 1) create node - 2) set node power state to 'off' - 3) check node power state has been set to 'off' - """ - self.set_node_power_state(self.node['uuid'], 'off') - node_state = self.show_node_states(self.node['uuid']) - self.assertEqual('power off', node_state['power_state']) - - def test_node_set_power_state_reboot_node_off(self): - """Test steps: - - 1) create node - 2) set node power state to 'off' - 3) check node power state has been set to 'off' - 4) set node power state to 'reboot' - 5) check node power state has been set to 'on' - """ - self.set_node_power_state(self.node['uuid'], 'off') - node_state = self.show_node_states(self.node['uuid']) - - self.assertEqual('power off', node_state['power_state']) - - self.set_node_power_state(self.node['uuid'], 'reboot') - node_state = self.show_node_states(self.node['uuid']) - - self.assertEqual('power on', node_state['power_state']) - - def test_node_set_power_state_reboot_node_on(self): - """Test steps: - - 1) create node - 2) set node power state to 'on' - 3) check node power state has been set to 'on' - 4) set node power state to 'reboot' - 5) check node power state has been set to 'on' - """ - self.set_node_power_state(self.node['uuid'], 'on') - node_state = self.show_node_states(self.node['uuid']) - - self.assertEqual('power on', node_state['power_state']) - - self.set_node_power_state(self.node['uuid'], 'reboot') - node_state = self.show_node_states(self.node['uuid']) - - self.assertEqual('power on', node_state['power_state']) diff --git a/ironicclient/tests/functional/test_port.py b/ironicclient/tests/functional/test_port.py deleted file mode 100644 index 095f731..0000000 --- a/ironicclient/tests/functional/test_port.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ironicclient.tests.functional import base - - -class PortSanityTestIronicClient(base.FunctionalTestBase): - """Sanity tests for testing actions with port. - - Smoke test for the Ironic CLI commands which checks basic actions with - port command like create, show, update, delete etc. - """ - - def setUp(self): - super(PortSanityTestIronicClient, self).setUp() - self.node = self.create_node() - self.port = self.create_port(self.node['uuid']) - - def test_port_create(self): - """Test steps: - - 1) create node in setUp() - 2) create port in setUp() - 3) check that port has been successfully created - """ - port_list_uuid = self.get_uuids_from_port_list() - self.assertIn(self.port['uuid'], port_list_uuid) - - def test_port_delete(self): - """Test steps: - - 1) create node in setUp() - 2) create port in setUp() - 3) check that port has been successfully created - 4) delete port - 5) check that port has been successfully deleted - """ - port_list_uuid = self.get_uuids_from_port_list() - self.assertIn(self.port['uuid'], port_list_uuid) - - self.delete_port(self.port['uuid']) - - port_list_uuid = self.get_uuids_from_port_list() - self.assertNotIn(self.port['uuid'], port_list_uuid) - - def test_port_show(self): - """Test steps: - - 1) create node in setUp() - 2) create port in setUp() - 3) check that port-show returns the same port UUID as port-create - """ - port_show = self.show_port(self.port['uuid']) - self.assertEqual(self.port['uuid'], port_show['uuid']) - - def test_port_show_field(self): - """Test steps: - - 1) create node in setUp() - 2) create port in setUp() - 3) show port with fields uuid, address, node_uuid - 4) check that only fields uuid, address, - node_uuid are the output fields - """ - fields = ['uuid', 'address', 'node_uuid'] - port_show = self.show_port(self.port['uuid'], - params='--fields {0} {1} {2}' - .format(*fields)) - self.assertTableHeaders(fields, port_show.keys()) - - def test_port_update(self): - """Test steps: - - 1) create node in setUp() - 2) create port in setUp() - 3) create node to replace - 4) update port replacing node - 5) check that port has been successfully updated - """ - node_to_replace = self.create_node() - updated_port = self.update_port(self.port['uuid'], - 'replace', - params='node_uuid={0}' - .format(node_to_replace['uuid'])) - - self.assertEqual(node_to_replace['uuid'], updated_port['node_uuid']) - self.assertNotEqual(self.port['node_uuid'], updated_port['node_uuid']) - - def test_port_list(self): - """Test steps: - - 1) create node and port in setUp() - 2) create one more node and port explicitly - 3) check that port-list contains UUIDs of created ports - 4) check that port-list contains Addresses of created ports - """ - other_node = self.create_node() - other_port = self.create_port(other_node['uuid']) - - port_list = self.list_ports() - uuids = {x['UUID'] for x in port_list} - self.assertTrue({self.port['uuid'], - other_port['uuid']}.issubset(uuids)) - addresses = {x['Address'] for x in port_list} - self.assertTrue({self.port['address'], - other_port['address']}.issubset(addresses)) - - def test_port_create_with_portgroup_uuid(self): - """Test steps: - - 1) Create node in setUp(). - 2) Create a port group. - 3) Create a port with specified port group UUID. - 4) Check port properties for portgroup_uuid. - """ - flag = '--ironic-api-version 1.25' - port_group = self.create_portgroup(self.node['uuid']) - port = self.create_port( - self.node['uuid'], - flags=flag, - params='--portgroup {0}'.format(port_group['uuid'])) - - self.assertEqual(port_group['uuid'], port['portgroup_uuid']) diff --git a/ironicclient/tests/functional/test_portgroup.py b/ironicclient/tests/functional/test_portgroup.py deleted file mode 100644 index 7d3f9ea..0000000 --- a/ironicclient/tests/functional/test_portgroup.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 ironicclient.tests.functional import base - - -class PortGroupSanityTest(base.FunctionalTestBase): - """Sanity tests for testing actions with port groups. - - Smoke test for the Ironic CLI port group subcommands: - create, show, update, delete, list, port-list. - """ - def setUp(self): - super(PortGroupSanityTest, self).setUp() - self.node = self.create_node() - self.port_group = self.create_portgroup(self.node['uuid']) - - def test_portgroup_create(self): - """Test steps: - - 1) Create node and port group in setUp(). - 2) Check that port group has been successfully created. - """ - portgroup_list_uuid = self.get_portgroup_uuids_from_portgroup_list() - self.assertIn(self.port_group['uuid'], portgroup_list_uuid) - - def test_portgroup_delete(self): - """Test steps: - - 1) Create node and port group in setUp(). - 2) Delete port group. - 3) Check that port group has been successfully deleted. - """ - self.delete_portgroup(self.port_group['uuid']) - portgroup_list_uuid = self.get_portgroup_uuids_from_portgroup_list() - self.assertNotIn(self.port_group['uuid'], portgroup_list_uuid) - - def test_portgroup_show(self): - """Test steps: - - 1) Create node and port group in setUp(). - 2) Check that portgroup-show returns the same UUID as portgroup-create. - """ - portgroup_show = self.show_portgroup(self.port_group['uuid']) - self.assertEqual(self.port_group['uuid'], portgroup_show['uuid']) - self.assertEqual(self.port_group['name'], portgroup_show['name']) - - def test_portgroup_list(self): - """Test steps: - - 1) Create node and port group in setUp(). - 2) Create one more node and port group. - 3) Check that portgroup-list contains UUIDs - of all created port groups. - """ - other_node = self.create_node() - other_portgroup = self.create_portgroup(other_node['uuid']) - - uuids = {x['UUID'] for x in self.list_portgroups()} - - self.assertTrue({self.port_group['uuid'], - other_portgroup['uuid']}.issubset(uuids)) - - def test_portgroup_update(self): - """Test steps: - - 1) Create node and port group in setUp(). - 2) Create node to replace. - 3) Set new node to maintenance. - 4) Update port group by replacing node. - 5) Check that port group has been successfully updated. - """ - node_to_replace = self.create_node() - self.set_node_maintenance(node_to_replace['uuid'], True) - updated_portgroup = self.update_portgroup( - self.port_group['uuid'], 'replace', params='node_uuid={0}' - .format(node_to_replace['uuid']) - ) - self.assertEqual(node_to_replace['uuid'], - updated_portgroup['node_uuid']) - self.assertNotEqual(self.port_group['node_uuid'], - updated_portgroup['node_uuid']) - - def test_portgroup_port_list(self): - """Test steps: - - 1) Create node and port group in setUp(). - 2) Create a port. - 3) Set node to maintenance. - 4) Attach port to the port group. - 5) List the ports associated with a port group. - 6) Check port UUID in list. - 7) Check port address in list. - """ - port = self.create_port(self.node['uuid']) - self.set_node_maintenance(self.node['uuid'], True) - self.update_port(port['uuid'], 'replace', - flags='--ironic-api-version 1.25', - params='portgroup_uuid={0}' - .format(self.port_group['uuid'])) - pg_port_list = self.portgroup_port_list(self.port_group['uuid']) - self.assertIn(port['uuid'], [x['UUID'] for x in pg_port_list]) - self.assertIn(port['address'], [x['Address'] for x in pg_port_list]) diff --git a/ironicclient/tests/functional/test_table_structure.py b/ironicclient/tests/functional/test_table_structure.py deleted file mode 100644 index a617cef..0000000 --- a/ironicclient/tests/functional/test_table_structure.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) 2015 Mirantis, Inc. -# -# 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 ironicclient.tests.functional import base - - -class TableStructureIronicCLITests(base.FunctionalTestBase): - """Basic, read-only table structure tests for Ironic CLI commands. - - Basic smoke tests for the Ironic CLI commands to check table structure - which do not require creating or modifying Ironic objects. - """ - - def test_chassis_list_table_structure(self): - """Test steps: - - 1) get chassis-list - 2) check table structure - """ - chassis_list_header = self.get_table_headers('chassis-list') - self.assertTableHeaders(['Description', 'UUID'], chassis_list_header) - - def test_node_list_table_structure(self): - """Test steps: - - 1) get node-list - 2) check table structure - """ - node_list_header = self.get_table_headers('node-list') - self.assertTableHeaders(['UUID', 'Name', 'Instance UUID', - 'Power State', 'Provisioning State', - 'Maintenance'], node_list_header) - - def test_port_list_table_structure(self): - """Test steps: - - 1) get port-list - 2) check table structure - """ - port_list_header = self.get_table_headers('port-list') - self.assertTableHeaders(['UUID', 'Address'], port_list_header) - - def test_driver_list_table_structure(self): - """Test steps: - - 1) get driver-list - 2) check table structure - """ - driver_list_header = self.get_table_headers('driver-list') - self.assertTableHeaders(['Supported driver(s)', 'Active host(s)'], - driver_list_header) diff --git a/ironicclient/tests/functional/utils.py b/ironicclient/tests/functional/utils.py deleted file mode 100644 index 49d2089..0000000 --- a/ironicclient/tests/functional/utils.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2015 Mirantis, Inc. -# -# 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 six - - -def get_dict_from_output(output): - """Parse list of dictionaries, return a dictionary. - - :param output: list of dictionaries - """ - obj = {} - for item in output: - obj[item['Property']] = six.text_type(item['Value']) - return obj - - -def get_object(object_list, object_value): - """Get Ironic object by value from list of Ironic objects. - - :param object_list: the output of the cmd - :param object_value: value to get - """ - for obj in object_list: - if object_value in obj.values(): - return obj diff --git a/ironicclient/tests/unit/__init__.py b/ironicclient/tests/unit/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/unit/common/__init__.py b/ironicclient/tests/unit/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/unit/common/apiclient/__init__.py b/ironicclient/tests/unit/common/apiclient/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/unit/common/apiclient/test_base.py b/ironicclient/tests/unit/common/apiclient/test_base.py deleted file mode 100644 index 9e2d6df..0000000 --- a/ironicclient/tests/unit/common/apiclient/test_base.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 mock -from oslotest import base as test_base - -from ironicclient.common.apiclient import base - - -class HumanResource(base.Resource): - HUMAN_ID = True - - -class HumanResourceManager(base.ManagerWithFind): - resource_class = HumanResource - - def list(self): - return self._list("/human_resources", "human_resources") - - def get(self, human_resource): - return self._get( - "/human_resources/%s" % base.getid(human_resource), - "human_resource") - - def update(self, human_resource, name): - body = { - "human_resource": { - "name": name, - }, - } - return self._put( - "/human_resources/%s" % base.getid(human_resource), - body, - "human_resource") - - -class CrudResource(base.Resource): - pass - - -class CrudResourceManager(base.CrudManager): - """Manager class for manipulating Identity crud_resources.""" - resource_class = CrudResource - collection_key = 'crud_resources' - key = 'crud_resource' - - def get(self, crud_resource): - return super(CrudResourceManager, self).get( - crud_resource_id=base.getid(crud_resource)) - - -class ResourceTest(test_base.BaseTestCase): - def test_resource_repr(self): - r = base.Resource(None, dict(foo="bar", baz="spam")) - self.assertEqual("", repr(r)) - - def test_getid(self): - class TmpObject(base.Resource): - id = "4" - self.assertEqual("4", base.getid(TmpObject(None, {}))) - - def test_human_id(self): - r = base.Resource(None, {"name": "1"}) - self.assertIsNone(r.human_id) - r = HumanResource(None, {"name": "1"}) - self.assertEqual("1", r.human_id) - r = HumanResource(None, {"name": None}) - self.assertIsNone(r.human_id) - - def test_two_resources_with_same_id_are_not_equal(self): - # Two resources with same ID: never equal if their info is not equal - r1 = base.Resource(None, {'id': 1, 'name': 'hi'}) - r2 = base.Resource(None, {'id': 1, 'name': 'hello'}) - self.assertNotEqual(r1, r2) - - def test_two_resources_with_same_id_and_info_are_equal(self): - # Two resources with same ID: equal if their info is equal - r1 = base.Resource(None, {'id': 1, 'name': 'hello'}) - r2 = base.Resource(None, {'id': 1, 'name': 'hello'}) - self.assertEqual(r1, r2) - - def test_two_resources_with_diff_type_are_not_equal(self): - # Two resoruces of different types: never equal - r1 = base.Resource(None, {'id': 1}) - r2 = HumanResource(None, {'id': 1}) - self.assertNotEqual(r1, r2) - - def test_two_resources_with_no_id_are_equal(self): - # Two resources with no ID: equal if their info is equal - r1 = base.Resource(None, {'name': 'joe', 'age': 12}) - r2 = base.Resource(None, {'name': 'joe', 'age': 12}) - self.assertEqual(r1, r2) - - -class BaseManagerTestCase(test_base.BaseTestCase): - - def setUp(self): - super(BaseManagerTestCase, self).setUp() - - self.response = mock.MagicMock() - self.http_client = mock.MagicMock() - self.http_client.get.return_value = self.response - self.http_client.post.return_value = self.response - - self.manager = base.BaseManager(self.http_client) - self.manager.resource_class = HumanResource - - def test_list(self): - self.response.json.return_value = {'human_resources': [{'id': 42}]} - expected = [HumanResource(self.manager, {'id': 42}, loaded=True)] - result = self.manager._list("/human_resources", "human_resources") - self.assertEqual(expected, result) - - def test_list_no_response_key(self): - self.response.json.return_value = [{'id': 42}] - expected = [HumanResource(self.manager, {'id': 42}, loaded=True)] - result = self.manager._list("/human_resources") - self.assertEqual(expected, result) - - def test_list_get(self): - self.manager._list("/human_resources", "human_resources") - self.manager.client.get.assert_called_with("/human_resources") - - def test_list_post(self): - self.manager._list("/human_resources", "human_resources", - json={'id': 42}) - self.manager.client.post.assert_called_with("/human_resources", - json={'id': 42}) - - def test_get(self): - self.response.json.return_value = {'human_resources': {'id': 42}} - expected = HumanResource(self.manager, {'id': 42}, loaded=True) - result = self.manager._get("/human_resources/42", "human_resources") - self.manager.client.get.assert_called_with("/human_resources/42") - self.assertEqual(expected, result) - - def test_get_no_response_key(self): - self.response.json.return_value = {'id': 42} - expected = HumanResource(self.manager, {'id': 42}, loaded=True) - result = self.manager._get("/human_resources/42") - self.manager.client.get.assert_called_with("/human_resources/42") - self.assertEqual(expected, result) - - def test_post(self): - self.response.json.return_value = {'human_resources': {'id': 42}} - expected = HumanResource(self.manager, {'id': 42}, loaded=True) - result = self.manager._post("/human_resources", - response_key="human_resources", - json={'id': 42}) - self.manager.client.post.assert_called_with("/human_resources", - json={'id': 42}) - self.assertEqual(expected, result) - - def test_post_return_raw(self): - self.response.json.return_value = {'human_resources': {'id': 42}} - result = self.manager._post("/human_resources", - response_key="human_resources", - json={'id': 42}, return_raw=True) - self.manager.client.post.assert_called_with("/human_resources", - json={'id': 42}) - self.assertEqual({'id': 42}, result) - - def test_post_no_response_key(self): - self.response.json.return_value = {'id': 42} - expected = HumanResource(self.manager, {'id': 42}, loaded=True) - result = self.manager._post("/human_resources", json={'id': 42}) - self.manager.client.post.assert_called_with("/human_resources", - json={'id': 42}) - self.assertEqual(expected, result) diff --git a/ironicclient/tests/unit/common/apiclient/test_exceptions.py b/ironicclient/tests/unit/common/apiclient/test_exceptions.py deleted file mode 100644 index 2ac5b39..0000000 --- a/ironicclient/tests/unit/common/apiclient/test_exceptions.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslotest import base as test_base -import six -from six.moves import http_client - -from ironicclient.common.apiclient import exceptions - - -class FakeResponse(object): - json_data = {} - - def __init__(self, **kwargs): - for key, value in kwargs.items(): - setattr(self, key, value) - - def json(self): - return self.json_data - - -class ExceptionsArgsTest(test_base.BaseTestCase): - - def assert_exception(self, ex_cls, method, url, status_code, json_data, - error_msg=None, error_details=None, - check_description=True): - ex = exceptions.from_response( - FakeResponse(status_code=status_code, - headers={"Content-Type": "application/json"}, - json_data=json_data), - method, - url) - self.assertIsInstance(ex, ex_cls) - if check_description: - expected_msg = error_msg or json_data["error"]["message"] - expected_details = error_details or json_data["error"]["details"] - self.assertEqual(expected_msg, ex.message) - self.assertEqual(expected_details, ex.details) - self.assertEqual(method, ex.method) - self.assertEqual(url, ex.url) - self.assertEqual(status_code, ex.http_status) - - def test_from_response_known(self): - method = "GET" - url = "/fake" - status_code = http_client.BAD_REQUEST - json_data = {"error": {"message": "fake message", - "details": "fake details"}} - self.assert_exception( - exceptions.BadRequest, method, url, status_code, json_data) - - def test_from_response_unknown(self): - method = "POST" - url = "/fake-unknown" - status_code = 499 - json_data = {"error": {"message": "fake unknown message", - "details": "fake unknown details"}} - self.assert_exception( - exceptions.HTTPClientError, method, url, status_code, json_data) - status_code = 600 - self.assert_exception( - exceptions.HttpError, method, url, status_code, json_data) - - def test_from_response_non_openstack(self): - method = "POST" - url = "/fake-unknown" - status_code = http_client.BAD_REQUEST - json_data = {"alien": 123} - self.assert_exception( - exceptions.BadRequest, method, url, status_code, json_data, - check_description=False) - - def test_from_response_with_different_response_format(self): - method = "GET" - url = "/fake-wsme" - status_code = http_client.BAD_REQUEST - json_data1 = {"error_message": {"debuginfo": None, - "faultcode": "Client", - "faultstring": "fake message"}} - message = six.text_type( - json_data1["error_message"]["faultstring"]) - details = six.text_type(json_data1) - self.assert_exception( - exceptions.BadRequest, method, url, status_code, json_data1, - message, details) - - json_data2 = {"badRequest": {"message": "fake message", - "code": http_client.BAD_REQUEST}} - message = six.text_type(json_data2["badRequest"]["message"]) - details = six.text_type(json_data2) - self.assert_exception( - exceptions.BadRequest, method, url, status_code, json_data2, - message, details) - - def test_from_response_with_text_response_format(self): - method = "GET" - url = "/fake-wsme" - status_code = http_client.BAD_REQUEST - text_data1 = "error_message: fake message" - - ex = exceptions.from_response( - FakeResponse(status_code=status_code, - headers={"Content-Type": "text/html"}, - text=text_data1), - method, - url) - self.assertIsInstance(ex, exceptions.BadRequest) - self.assertEqual(text_data1, ex.details) - self.assertEqual(method, ex.method) - self.assertEqual(url, ex.url) - self.assertEqual(status_code, ex.http_status) - - def test_from_response_with_text_response_format_with_no_body(self): - method = "GET" - url = "/fake-wsme" - status_code = http_client.UNAUTHORIZED - - ex = exceptions.from_response( - FakeResponse(status_code=status_code, - headers={"Content-Type": "text/html"}), - method, - url) - self.assertIsInstance(ex, exceptions.Unauthorized) - self.assertEqual('', ex.details) - self.assertEqual(method, ex.method) - self.assertEqual(url, ex.url) - self.assertEqual(status_code, ex.http_status) diff --git a/ironicclient/tests/unit/common/test_base.py b/ironicclient/tests/unit/common/test_base.py deleted file mode 100644 index 3575e33..0000000 --- a/ironicclient/tests/unit/common/test_base.py +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 copy - -import mock -import testtools - -from ironicclient.common import base -from ironicclient import exc -from ironicclient.tests.unit import utils - - -TESTABLE_RESOURCE = { - 'uuid': '11111111-2222-3333-4444-555555555555', - 'attribute1': '1', - 'attribute2': '2', -} - -CREATE_TESTABLE_RESOURCE = copy.deepcopy(TESTABLE_RESOURCE) -del CREATE_TESTABLE_RESOURCE['uuid'] - -INVALID_ATTRIBUTE_TESTABLE_RESOURCE = { - 'non-existent-attribute': 'blablabla', - 'attribute1': '1', - 'attribute2': '2', -} - -UPDATED_TESTABLE_RESOURCE = copy.deepcopy(TESTABLE_RESOURCE) -NEW_ATTRIBUTE_VALUE = 'brand-new-attribute-value' -UPDATED_TESTABLE_RESOURCE['attribute1'] = NEW_ATTRIBUTE_VALUE - -fake_responses = { - '/v1/testableresources': - { - 'GET': ( - {}, - {"testableresources": [TESTABLE_RESOURCE]}, - ), - 'POST': ( - {}, - CREATE_TESTABLE_RESOURCE, - ), - }, - '/v1/testableresources/%s' % TESTABLE_RESOURCE['uuid']: - { - 'GET': ( - {}, - TESTABLE_RESOURCE, - ), - 'DELETE': ( - {}, - None, - ), - 'PATCH': ( - {}, - UPDATED_TESTABLE_RESOURCE, - ), - }, - -} - - -class TestableResource(base.Resource): - def __repr__(self): - return "" % self._info - - -class TestableManager(base.CreateManager): - resource_class = TestableResource - _creation_attributes = ['attribute1', 'attribute2'] - _resource_name = 'testableresources' - - def _path(self, id=None): - return ('/v1/testableresources/%s' % id if id - else '/v1/testableresources') - - def get(self, testable_resource_id, fields=None): - return self._get(resource_id=testable_resource_id, - fields=fields) - - def delete(self, testable_resource_id): - return self._delete(resource_id=testable_resource_id) - - def update(self, testable_resource_id, patch): - return self._update(resource_id=testable_resource_id, - patch=patch) - - -class ManagerTestCase(testtools.TestCase): - - def setUp(self): - super(ManagerTestCase, self).setUp() - self.api = utils.FakeAPI(fake_responses) - self.manager = TestableManager(self.api) - - def test_create(self): - resource = self.manager.create(**CREATE_TESTABLE_RESOURCE) - expect = [ - ('POST', '/v1/testableresources', {}, CREATE_TESTABLE_RESOURCE), - ] - self.assertEqual(expect, self.api.calls) - self.assertTrue(resource) - self.assertIsInstance(resource, TestableResource) - - def test_create_with_invalid_attribute(self): - self.assertRaisesRegex(exc.InvalidAttribute, "non-existent-attribute", - self.manager.create, - **INVALID_ATTRIBUTE_TESTABLE_RESOURCE) - - def test__get(self): - resource_id = TESTABLE_RESOURCE['uuid'] - resource = self.manager._get(resource_id) - expect = [ - ('GET', '/v1/testableresources/%s' % resource_id, - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(resource_id, resource.uuid) - self.assertEqual(TESTABLE_RESOURCE['attribute1'], resource.attribute1) - - def test__get_invalid_resource_id_raises(self): - resource_ids = [[], {}, False, '', 0, None, ()] - for resource_id in resource_ids: - self.assertRaises(exc.ValidationError, self.manager._get, - resource_id=resource_id) - - def test__get_as_dict(self): - resource_id = TESTABLE_RESOURCE['uuid'] - resource = self.manager._get_as_dict(resource_id) - expect = [ - ('GET', '/v1/testableresources/%s' % resource_id, - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(TESTABLE_RESOURCE, resource) - - @mock.patch.object(base.Manager, '_get', autospec=True) - def test__get_as_dict_empty(self, mock_get): - mock_get.return_value = None - resource_id = TESTABLE_RESOURCE['uuid'] - resource = self.manager._get_as_dict(resource_id) - mock_get.assert_called_once_with(mock.ANY, resource_id, fields=None) - self.assertEqual({}, resource) - - def test_get(self): - resource = self.manager.get(TESTABLE_RESOURCE['uuid']) - expect = [ - ('GET', '/v1/testableresources/%s' % TESTABLE_RESOURCE['uuid'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(TESTABLE_RESOURCE['uuid'], resource.uuid) - self.assertEqual(TESTABLE_RESOURCE['attribute1'], resource.attribute1) - - def test_update(self): - patch = {'op': 'replace', - 'value': NEW_ATTRIBUTE_VALUE, - 'path': '/attribute1'} - resource = self.manager.update( - testable_resource_id=TESTABLE_RESOURCE['uuid'], - patch=patch - ) - expect = [ - ('PATCH', '/v1/testableresources/%s' % TESTABLE_RESOURCE['uuid'], - {}, patch), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NEW_ATTRIBUTE_VALUE, resource.attribute1) - - def test_delete(self): - resource = self.manager.delete( - testable_resource_id=TESTABLE_RESOURCE['uuid'] - ) - expect = [ - ('DELETE', '/v1/testableresources/%s' % TESTABLE_RESOURCE['uuid'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(resource) diff --git a/ironicclient/tests/unit/common/test_cliutils.py b/ironicclient/tests/unit/common/test_cliutils.py deleted file mode 100644 index 5984b5f..0000000 --- a/ironicclient/tests/unit/common/test_cliutils.py +++ /dev/null @@ -1,740 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# -# 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 sys - -import fixtures -import mock -from oslotest import base as test_base -import six - -from ironicclient.common import cliutils - - -class ValidateArgsTest(test_base.BaseTestCase): - - def test_lambda_no_args(self): - cliutils.validate_args(lambda: None) - - def _test_lambda_with_args(self, *args, **kwargs): - cliutils.validate_args(lambda x, y: None, *args, **kwargs) - - def test_lambda_positional_args(self): - self._test_lambda_with_args(1, 2) - - def test_lambda_kwargs(self): - self._test_lambda_with_args(x=1, y=2) - - def test_lambda_mixed_kwargs(self): - self._test_lambda_with_args(1, y=2) - - def test_lambda_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_lambda_with_args) - - def test_lambda_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_lambda_with_args, 1) - - def test_lambda_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_lambda_with_args, y=2) - - def _test_lambda_with_default(self, *args, **kwargs): - cliutils.validate_args(lambda x, y, z=3: None, *args, **kwargs) - - def test_lambda_positional_args_with_default(self): - self._test_lambda_with_default(1, 2) - - def test_lambda_kwargs_with_default(self): - self._test_lambda_with_default(x=1, y=2) - - def test_lambda_mixed_kwargs_with_default(self): - self._test_lambda_with_default(1, y=2) - - def test_lambda_positional_args_all_with_default(self): - self._test_lambda_with_default(1, 2, 3) - - def test_lambda_kwargs_all_with_default(self): - self._test_lambda_with_default(x=1, y=2, z=3) - - def test_lambda_mixed_kwargs_all_with_default(self): - self._test_lambda_with_default(1, y=2, z=3) - - def test_lambda_with_default_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_lambda_with_default) - - def test_lambda_with_default_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_lambda_with_default, 1) - - def test_lambda_with_default_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_lambda_with_default, y=2) - - def test_lambda_with_default_missing_args4(self): - self.assertRaises(cliutils.MissingArgs, - self._test_lambda_with_default, y=2, z=3) - - def test_function_no_args(self): - def func(): - pass - cliutils.validate_args(func) - - def _test_function_with_args(self, *args, **kwargs): - def func(x, y): - pass - cliutils.validate_args(func, *args, **kwargs) - - def test_function_positional_args(self): - self._test_function_with_args(1, 2) - - def test_function_kwargs(self): - self._test_function_with_args(x=1, y=2) - - def test_function_mixed_kwargs(self): - self._test_function_with_args(1, y=2) - - def test_function_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_function_with_args) - - def test_function_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_function_with_args, 1) - - def test_function_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_function_with_args, y=2) - - def _test_function_with_default(self, *args, **kwargs): - def func(x, y, z=3): - pass - cliutils.validate_args(func, *args, **kwargs) - - def test_function_positional_args_with_default(self): - self._test_function_with_default(1, 2) - - def test_function_kwargs_with_default(self): - self._test_function_with_default(x=1, y=2) - - def test_function_mixed_kwargs_with_default(self): - self._test_function_with_default(1, y=2) - - def test_function_positional_args_all_with_default(self): - self._test_function_with_default(1, 2, 3) - - def test_function_kwargs_all_with_default(self): - self._test_function_with_default(x=1, y=2, z=3) - - def test_function_mixed_kwargs_all_with_default(self): - self._test_function_with_default(1, y=2, z=3) - - def test_function_with_default_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_function_with_default) - - def test_function_with_default_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_function_with_default, 1) - - def test_function_with_default_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_function_with_default, y=2) - - def test_function_with_default_missing_args4(self): - self.assertRaises(cliutils.MissingArgs, - self._test_function_with_default, y=2, z=3) - - def test_bound_method_no_args(self): - class Foo(object): - def bar(self): - pass - cliutils.validate_args(Foo().bar) - - def _test_bound_method_with_args(self, *args, **kwargs): - class Foo(object): - def bar(self, x, y): - pass - cliutils.validate_args(Foo().bar, *args, **kwargs) - - def test_bound_method_positional_args(self): - self._test_bound_method_with_args(1, 2) - - def test_bound_method_kwargs(self): - self._test_bound_method_with_args(x=1, y=2) - - def test_bound_method_mixed_kwargs(self): - self._test_bound_method_with_args(1, y=2) - - def test_bound_method_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_bound_method_with_args) - - def test_bound_method_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_bound_method_with_args, 1) - - def test_bound_method_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_bound_method_with_args, y=2) - - def _test_bound_method_with_default(self, *args, **kwargs): - class Foo(object): - def bar(self, x, y, z=3): - pass - cliutils.validate_args(Foo().bar, *args, **kwargs) - - def test_bound_method_positional_args_with_default(self): - self._test_bound_method_with_default(1, 2) - - def test_bound_method_kwargs_with_default(self): - self._test_bound_method_with_default(x=1, y=2) - - def test_bound_method_mixed_kwargs_with_default(self): - self._test_bound_method_with_default(1, y=2) - - def test_bound_method_positional_args_all_with_default(self): - self._test_bound_method_with_default(1, 2, 3) - - def test_bound_method_kwargs_all_with_default(self): - self._test_bound_method_with_default(x=1, y=2, z=3) - - def test_bound_method_mixed_kwargs_all_with_default(self): - self._test_bound_method_with_default(1, y=2, z=3) - - def test_bound_method_with_default_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_bound_method_with_default) - - def test_bound_method_with_default_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_bound_method_with_default, 1) - - def test_bound_method_with_default_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_bound_method_with_default, y=2) - - def test_bound_method_with_default_missing_args4(self): - self.assertRaises(cliutils.MissingArgs, - self._test_bound_method_with_default, y=2, z=3) - - def test_unbound_method_no_args(self): - class Foo(object): - def bar(self): - pass - cliutils.validate_args(Foo.bar, Foo()) - - def _test_unbound_method_with_args(self, *args, **kwargs): - class Foo(object): - def bar(self, x, y): - pass - cliutils.validate_args(Foo.bar, Foo(), *args, **kwargs) - - def test_unbound_method_positional_args(self): - self._test_unbound_method_with_args(1, 2) - - def test_unbound_method_kwargs(self): - self._test_unbound_method_with_args(x=1, y=2) - - def test_unbound_method_mixed_kwargs(self): - self._test_unbound_method_with_args(1, y=2) - - def test_unbound_method_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_unbound_method_with_args) - - def test_unbound_method_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_unbound_method_with_args, 1) - - def test_unbound_method_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_unbound_method_with_args, y=2) - - def _test_unbound_method_with_default(self, *args, **kwargs): - class Foo(object): - def bar(self, x, y, z=3): - pass - cliutils.validate_args(Foo.bar, Foo(), *args, **kwargs) - - def test_unbound_method_positional_args_with_default(self): - self._test_unbound_method_with_default(1, 2) - - def test_unbound_method_kwargs_with_default(self): - self._test_unbound_method_with_default(x=1, y=2) - - def test_unbound_method_mixed_kwargs_with_default(self): - self._test_unbound_method_with_default(1, y=2) - - def test_unbound_method_with_default_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_unbound_method_with_default) - - def test_unbound_method_with_default_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_unbound_method_with_default, 1) - - def test_unbound_method_with_default_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_unbound_method_with_default, y=2) - - def test_unbound_method_with_default_missing_args4(self): - self.assertRaises(cliutils.MissingArgs, - self._test_unbound_method_with_default, y=2, z=3) - - def test_class_method_no_args(self): - class Foo(object): - @classmethod - def bar(cls): - pass - cliutils.validate_args(Foo.bar) - - def _test_class_method_with_args(self, *args, **kwargs): - class Foo(object): - @classmethod - def bar(cls, x, y): - pass - cliutils.validate_args(Foo.bar, *args, **kwargs) - - def test_class_method_positional_args(self): - self._test_class_method_with_args(1, 2) - - def test_class_method_kwargs(self): - self._test_class_method_with_args(x=1, y=2) - - def test_class_method_mixed_kwargs(self): - self._test_class_method_with_args(1, y=2) - - def test_class_method_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_class_method_with_args) - - def test_class_method_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_class_method_with_args, 1) - - def test_class_method_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_class_method_with_args, y=2) - - def _test_class_method_with_default(self, *args, **kwargs): - class Foo(object): - @classmethod - def bar(cls, x, y, z=3): - pass - cliutils.validate_args(Foo.bar, *args, **kwargs) - - def test_class_method_positional_args_with_default(self): - self._test_class_method_with_default(1, 2) - - def test_class_method_kwargs_with_default(self): - self._test_class_method_with_default(x=1, y=2) - - def test_class_method_mixed_kwargs_with_default(self): - self._test_class_method_with_default(1, y=2) - - def test_class_method_with_default_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_class_method_with_default) - - def test_class_method_with_default_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_class_method_with_default, 1) - - def test_class_method_with_default_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_class_method_with_default, y=2) - - def test_class_method_with_default_missing_args4(self): - self.assertRaises(cliutils.MissingArgs, - self._test_class_method_with_default, y=2, z=3) - - def test_static_method_no_args(self): - class Foo(object): - @staticmethod - def bar(): - pass - cliutils.validate_args(Foo.bar) - - def _test_static_method_with_args(self, *args, **kwargs): - class Foo(object): - @staticmethod - def bar(x, y): - pass - cliutils.validate_args(Foo.bar, *args, **kwargs) - - def test_static_method_positional_args(self): - self._test_static_method_with_args(1, 2) - - def test_static_method_kwargs(self): - self._test_static_method_with_args(x=1, y=2) - - def test_static_method_mixed_kwargs(self): - self._test_static_method_with_args(1, y=2) - - def test_static_method_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_static_method_with_args) - - def test_static_method_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_static_method_with_args, 1) - - def test_static_method_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_static_method_with_args, y=2) - - def _test_static_method_with_default(self, *args, **kwargs): - class Foo(object): - @staticmethod - def bar(x, y, z=3): - pass - cliutils.validate_args(Foo.bar, *args, **kwargs) - - def test_static_method_positional_args_with_default(self): - self._test_static_method_with_default(1, 2) - - def test_static_method_kwargs_with_default(self): - self._test_static_method_with_default(x=1, y=2) - - def test_static_method_mixed_kwargs_with_default(self): - self._test_static_method_with_default(1, y=2) - - def test_static_method_with_default_missing_args1(self): - self.assertRaises(cliutils.MissingArgs, - self._test_static_method_with_default) - - def test_static_method_with_default_missing_args2(self): - self.assertRaises(cliutils.MissingArgs, - self._test_static_method_with_default, 1) - - def test_static_method_with_default_missing_args3(self): - self.assertRaises(cliutils.MissingArgs, - self._test_static_method_with_default, y=2) - - def test_static_method_with_default_missing_args4(self): - self.assertRaises(cliutils.MissingArgs, - self._test_static_method_with_default, y=2, z=3) - - -class _FakeResult(object): - def __init__(self, name, value): - self.name = name - self.value = value - - -class PrintResultTestCase(test_base.BaseTestCase): - - def setUp(self): - super(PrintResultTestCase, self).setUp() - self.mock_add_row = mock.MagicMock() - self.useFixture(fixtures.MonkeyPatch( - "prettytable.PrettyTable.add_row", - self.mock_add_row)) - self.mock_get_string = mock.MagicMock(return_value="") - self.useFixture(fixtures.MonkeyPatch( - "prettytable.PrettyTable.get_string", - self.mock_get_string)) - self.mock_init = mock.MagicMock(return_value=None) - self.useFixture(fixtures.MonkeyPatch( - "prettytable.PrettyTable.__init__", - self.mock_init)) - # NOTE(dtantsur): won't work with mocked __init__ - self.useFixture(fixtures.MonkeyPatch( - "prettytable.PrettyTable.align", - mock.MagicMock())) - - def test_print_list_sort_by_str(self): - objs = [_FakeResult("k1", 1), - _FakeResult("k3", 2), - _FakeResult("k2", 3)] - - cliutils.print_list(objs, ["Name", "Value"], sortby_index=0) - - self.assertEqual(self.mock_add_row.call_args_list, - [mock.call(["k1", 1]), - mock.call(["k3", 2]), - mock.call(["k2", 3])]) - self.mock_get_string.assert_called_with(sortby="Name") - self.mock_init.assert_called_once_with(["Name", "Value"]) - - def test_print_list_sort_by_integer(self): - objs = [_FakeResult("k1", 1), - _FakeResult("k2", 3), - _FakeResult("k3", 2)] - - cliutils.print_list(objs, ["Name", "Value"], sortby_index=1) - - self.assertEqual(self.mock_add_row.call_args_list, - [mock.call(["k1", 1]), - mock.call(["k2", 3]), - mock.call(["k3", 2])]) - self.mock_get_string.assert_called_with(sortby="Value") - self.mock_init.assert_called_once_with(["Name", "Value"]) - - def test_print_list_sort_by_none(self): - objs = [_FakeResult("k1", 1), - _FakeResult("k3", 3), - _FakeResult("k2", 2)] - - cliutils.print_list(objs, ["Name", "Value"], sortby_index=None) - - self.assertEqual(self.mock_add_row.call_args_list, - [mock.call(["k1", 1]), - mock.call(["k3", 3]), - mock.call(["k2", 2])]) - self.mock_get_string.assert_called_with() - self.mock_init.assert_called_once_with(["Name", "Value"]) - - def test_print_list_dict(self): - objs = [{'name': 'k1', 'value': 1}, - {'name': 'k2', 'value': 2}] - cliutils.print_list(objs, ["Name", "Value"], sortby_index=None) - - self.assertEqual(self.mock_add_row.call_args_list, - [mock.call(["k1", 1]), - mock.call(["k2", 2])]) - self.mock_get_string.assert_called_with() - self.mock_init.assert_called_once_with(["Name", "Value"]) - - def test_print_dict(self): - cliutils.print_dict({"K": "k", "Key": "Value"}) - cliutils.print_dict({"K": "k", "Key": "Long\\nValue"}) - self.mock_add_row.assert_has_calls([ - mock.call(["K", "k"]), - mock.call(["Key", "Value"]), - mock.call(["K", "k"]), - mock.call(["Key", "Long"]), - mock.call(["", "Value"])], - any_order=True) - - def test_print_list_field_labels(self): - objs = [_FakeResult("k1", 1), - _FakeResult("k3", 3), - _FakeResult("k2", 2)] - field_labels = ["Another Name", "Another Value"] - - cliutils.print_list(objs, ["Name", "Value"], sortby_index=None, - field_labels=field_labels) - - self.assertEqual(self.mock_add_row.call_args_list, - [mock.call(["k1", 1]), - mock.call(["k3", 3]), - mock.call(["k2", 2])]) - self.mock_init.assert_called_once_with(field_labels) - - def test_print_list_field_labels_sort(self): - objs = [_FakeResult("k1", 1), - _FakeResult("k3", 3), - _FakeResult("k2", 2)] - field_labels = ["Another Name", "Another Value"] - - cliutils.print_list(objs, ["Name", "Value"], sortby_index=0, - field_labels=field_labels) - - self.assertEqual(self.mock_add_row.call_args_list, - [mock.call(["k1", 1]), - mock.call(["k3", 3]), - mock.call(["k2", 2])]) - self.mock_init.assert_called_once_with(field_labels) - self.mock_get_string.assert_called_with(sortby="Another Name") - - def test_print_list_field_labels_too_many(self): - objs = [_FakeResult("k1", 1), - _FakeResult("k3", 3), - _FakeResult("k2", 2)] - field_labels = ["Another Name", "Another Value", "Redundant"] - - self.assertRaises(ValueError, cliutils.print_list, - objs, ["Name", "Value"], sortby_index=None, - field_labels=field_labels) - - -class PrintResultStringTestCase(test_base.BaseTestCase): - - def test_print_list_string(self): - objs = [_FakeResult("k1", 1)] - field_labels = ["Another Name", "Another Value"] - - orig = sys.stdout - sys.stdout = six.StringIO() - cliutils.print_list(objs, ["Name", "Value"], sortby_index=0, - field_labels=field_labels) - out = sys.stdout.getvalue() - sys.stdout.close() - sys.stdout = orig - expected = '''\ -+--------------+---------------+ -| Another Name | Another Value | -+--------------+---------------+ -| k1 | 1 | -+--------------+---------------+ -''' - self.assertEqual(expected, out) - - def test_print_list_string_json(self): - objs = [_FakeResult("k1", 1)] - field_labels = ["Another Name", "Another Value"] - - orig = sys.stdout - sys.stdout = six.StringIO() - cliutils.print_list(objs, ["Name", "Value"], sortby_index=0, - field_labels=field_labels, json_flag=True) - out = sys.stdout.getvalue() - sys.stdout.close() - sys.stdout = orig - - expected = [{"name": "k1", "value": 1}] - self.assertEqual(expected, json.loads(out)) - - def test_print_dict_string(self): - orig = sys.stdout - sys.stdout = six.StringIO() - cliutils.print_dict({"K": "k", "Key": "Value"}) - out = sys.stdout.getvalue() - sys.stdout.close() - sys.stdout = orig - expected = '''\ -+----------+-------+ -| Property | Value | -+----------+-------+ -| K | k | -| Key | Value | -+----------+-------+ -''' - self.assertEqual(expected, out) - - def test_print_dict_string_json(self): - orig = sys.stdout - sys.stdout = six.StringIO() - cliutils.print_dict({"K": "k", "Key": "Value"}, json_flag=True) - out = sys.stdout.getvalue() - sys.stdout.close() - sys.stdout = orig - expected = {"K": "k", "Key": "Value"} - self.assertEqual(expected, json.loads(out)) - - def test_print_dict_string_custom_headers(self): - orig = sys.stdout - sys.stdout = six.StringIO() - cliutils.print_dict({"K": "k", "Key": "Value"}, dict_property='Foo', - dict_value='Bar') - out = sys.stdout.getvalue() - sys.stdout.close() - sys.stdout = orig - expected = '''\ -+-----+-------+ -| Foo | Bar | -+-----+-------+ -| K | k | -| Key | Value | -+-----+-------+ -''' - self.assertEqual(expected, out) - - def test_print_dict_string_sorted(self): - orig = sys.stdout - sys.stdout = six.StringIO() - cliutils.print_dict({"Foo": "k", "Bar": "Value"}) - out = sys.stdout.getvalue() - sys.stdout.close() - sys.stdout = orig - expected = '''\ -+----------+-------+ -| Property | Value | -+----------+-------+ -| Bar | Value | -| Foo | k | -+----------+-------+ -''' - self.assertEqual(expected, out) - - def test_print_dict_negative_wrap(self): - dct = {"K": "k", "Key": "Value"} - self.assertRaises(ValueError, cliutils.print_dict, dct, wrap=-10) - - -class DecoratorsTestCase(test_base.BaseTestCase): - - def test_arg(self): - func_args = [("--image", ), ("--flavor", )] - func_kwargs = [dict(default=None, - metavar=""), - dict(default=None, - metavar="")] - - @cliutils.arg(*func_args[1], **func_kwargs[1]) - @cliutils.arg(*func_args[0], **func_kwargs[0]) - def dummy_func(): - pass - - self.assertTrue(hasattr(dummy_func, "arguments")) - self.assertEqual(len(dummy_func.arguments), 2) - for args_kwargs in zip(func_args, func_kwargs): - self.assertIn(args_kwargs, dummy_func.arguments) - - def test_unauthenticated(self): - def dummy_func(): - pass - - self.assertFalse(cliutils.isunauthenticated(dummy_func)) - dummy_func = cliutils.unauthenticated(dummy_func) - self.assertTrue(cliutils.isunauthenticated(dummy_func)) - - -class EnvTestCase(test_base.BaseTestCase): - - def test_env(self): - env = {"alpha": "a", "beta": "b"} - self.useFixture(fixtures.MonkeyPatch("os.environ", env)) - self.assertEqual(env["beta"], cliutils.env("beta")) - self.assertEqual(env["beta"], cliutils.env("beta", "alpha")) - self.assertEqual(env["alpha"], cliutils.env("alpha", "beta")) - self.assertEqual(env["beta"], cliutils.env("gamma", "beta")) - self.assertEqual("", cliutils.env("gamma")) - self.assertEqual("c", cliutils.env("gamma", default="c")) - - -class GetPasswordTestCase(test_base.BaseTestCase): - - def setUp(self): - super(GetPasswordTestCase, self).setUp() - - class FakeFile(object): - def isatty(self): - return True - - self.useFixture(fixtures.MonkeyPatch("sys.stdin", FakeFile())) - - def test_get_password(self): - self.useFixture(fixtures.MonkeyPatch("getpass.getpass", - lambda prompt: "mellon")) - self.assertEqual("mellon", cliutils.get_password()) - - def test_get_password_verify(self): - env = {"OS_VERIFY_PASSWORD": "True"} - self.useFixture(fixtures.MonkeyPatch("os.environ", env)) - self.useFixture(fixtures.MonkeyPatch("getpass.getpass", - lambda prompt: "mellon")) - self.assertEqual("mellon", cliutils.get_password()) - - def test_get_password_verify_failure(self): - env = {"OS_VERIFY_PASSWORD": "True"} - self.useFixture(fixtures.MonkeyPatch("os.environ", env)) - self.useFixture(fixtures.MonkeyPatch("getpass.getpass", - lambda prompt: prompt)) - self.assertIsNone(cliutils.get_password()) diff --git a/ironicclient/tests/unit/common/test_filecache.py b/ironicclient/tests/unit/common/test_filecache.py deleted file mode 100644 index 5df4046..0000000 --- a/ironicclient/tests/unit/common/test_filecache.py +++ /dev/null @@ -1,178 +0,0 @@ -# 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 os - -import dogpile.cache -import mock - -from ironicclient.common import filecache -from ironicclient.tests.unit import utils - - -class FileCacheTest(utils.BaseTestCase): - - def test__build_key_ok(self): - result = filecache._build_key('localhost', '5000') - self.assertEqual('localhost:5000', result) - - def test__build_key_none(self): - result = filecache._build_key(None, None) - self.assertEqual('None:None', result) - - @mock.patch.object(os.environ, 'get', autospec=True) - @mock.patch.object(os.path, 'exists', autospec=True) - @mock.patch.object(os, 'makedirs', autospec=True) - @mock.patch.object(dogpile.cache, 'make_region', autospec=True) - def test__get_cache_mkdir(self, mock_makeregion, mock_makedirs, - mock_exists, mock_get): - cache_val = 6 - # If not present in the env, get will return the defaulted value - mock_get.return_value = filecache.DEFAULT_EXPIRY - filecache.CACHE = None - mock_exists.return_value = False - cache_region = mock.Mock(spec=dogpile.cache.region.CacheRegion) - cache_region.configure.return_value = cache_val - mock_makeregion.return_value = cache_region - self.assertEqual(cache_val, filecache._get_cache()) - mock_exists.assert_called_once_with(filecache.CACHE_DIR) - mock_makedirs.assert_called_once_with(filecache.CACHE_DIR) - mock_get.assert_called_once_with(filecache.CACHE_EXPIRY_ENV_VAR, - mock.ANY) - cache_region.configure.assert_called_once_with( - mock.ANY, - arguments=mock.ANY, - expiration_time=filecache.DEFAULT_EXPIRY) - - @mock.patch.object(os.environ, 'get', autospec=True) - @mock.patch.object(os.path, 'exists', autospec=True) - @mock.patch.object(os, 'makedirs', autospec=True) - @mock.patch.object(dogpile.cache, 'make_region', autospec=True) - def test__get_cache_expiry_set(self, mock_makeregion, mock_makedirs, - mock_exists, mock_get): - cache_val = 5643 - cache_expiry = '78' - mock_get.return_value = cache_expiry - filecache.CACHE = None - mock_exists.return_value = False - cache_region = mock.Mock(spec=dogpile.cache.region.CacheRegion) - cache_region.configure.return_value = cache_val - mock_makeregion.return_value = cache_region - self.assertEqual(cache_val, filecache._get_cache()) - mock_get.assert_called_once_with(filecache.CACHE_EXPIRY_ENV_VAR, - mock.ANY) - cache_region.configure.assert_called_once_with( - mock.ANY, - arguments=mock.ANY, - expiration_time=int(cache_expiry)) - - @mock.patch.object(filecache.LOG, 'warning', autospec=True) - @mock.patch.object(os.environ, 'get', autospec=True) - @mock.patch.object(os.path, 'exists', autospec=True) - @mock.patch.object(os, 'makedirs', autospec=True) - @mock.patch.object(dogpile.cache, 'make_region', autospec=True) - def test__get_cache_expiry_set_invalid(self, mock_makeregion, - mock_makedirs, mock_exists, - mock_get, mock_log): - cache_val = 5643 - cache_expiry = 'Rollenhagen' - mock_get.return_value = cache_expiry - filecache.CACHE = None - mock_exists.return_value = False - cache_region = mock.Mock(spec=dogpile.cache.region.CacheRegion) - cache_region.configure.return_value = cache_val - mock_makeregion.return_value = cache_region - self.assertEqual(cache_val, filecache._get_cache()) - mock_get.assert_called_once_with(filecache.CACHE_EXPIRY_ENV_VAR, - mock.ANY) - cache_region.configure.assert_called_once_with( - mock.ANY, - arguments=mock.ANY, - expiration_time=filecache.DEFAULT_EXPIRY) - log_dict = {'curr_val': cache_expiry, - 'default': filecache.DEFAULT_EXPIRY, - 'env_var': filecache.CACHE_EXPIRY_ENV_VAR} - mock_log.assert_called_once_with(mock.ANY, log_dict) - - @mock.patch.object(os.path, 'exists', autospec=True) - @mock.patch.object(os, 'makedirs', autospec=True) - def test__get_cache_dir_already_exists(self, mock_makedirs, mock_exists): - cache_val = 5552368 - mock_exists.return_value = True - filecache.CACHE = cache_val - self.assertEqual(cache_val, filecache._get_cache()) - self.assertEqual(0, mock_exists.call_count) - self.assertEqual(0, mock_makedirs.call_count) - - @mock.patch.object(dogpile.cache.region, 'CacheRegion', autospec=True) - @mock.patch.object(filecache, '_get_cache', autospec=True) - def test_save_data_ok(self, mock_get_cache, mock_cache): - mock_get_cache.return_value = mock_cache - host = 'fred' - port = '1234' - hostport = '%s:%s' % (host, port) - data = 'some random data' - filecache.save_data(host, port, data) - mock_cache.set.assert_called_once_with(hostport, data) - - @mock.patch.object(os.path, 'isfile', autospec=True) - @mock.patch.object(dogpile.cache.region, 'CacheRegion', autospec=True) - @mock.patch.object(filecache, '_get_cache', autospec=True) - def test_retrieve_data_ok(self, mock_get_cache, mock_cache, mock_isfile): - s = 'spam' - mock_isfile.return_value = True - mock_cache.get.return_value = s - mock_get_cache.return_value = mock_cache - host = 'fred' - port = '1234' - hostport = '%s:%s' % (host, port) - result = filecache.retrieve_data(host, port) - mock_cache.get.assert_called_once_with(hostport, expiration_time=None) - self.assertEqual(s, result) - - @mock.patch.object(os.path, 'isfile', autospec=True) - @mock.patch.object(dogpile.cache.region, 'CacheRegion', autospec=True) - @mock.patch.object(filecache, '_get_cache', autospec=True) - def test_retrieve_data_ok_with_expiry(self, mock_get_cache, mock_cache, - mock_isfile): - s = 'spam' - mock_isfile.return_value = True - mock_cache.get.return_value = s - mock_get_cache.return_value = mock_cache - host = 'fred' - port = '1234' - expiry = '987' - hostport = '%s:%s' % (host, port) - result = filecache.retrieve_data(host, port, expiry) - mock_cache.get.assert_called_once_with(hostport, - expiration_time=expiry) - self.assertEqual(s, result) - - @mock.patch.object(os.path, 'isfile', autospec=True) - @mock.patch.object(dogpile.cache.region, 'CacheRegion', autospec=True) - @mock.patch.object(filecache, '_get_cache', autospec=True) - def test_retrieve_data_not_found(self, mock_get_cache, mock_cache, - mock_isfile): - mock_isfile.return_value = True - mock_cache.get.return_value = dogpile.cache.api.NO_VALUE - mock_get_cache.return_value = mock_cache - host = 'fred' - port = '1234' - hostport = '%s:%s' % (host, port) - result = filecache.retrieve_data(host, port) - mock_cache.get.assert_called_once_with(hostport, expiration_time=None) - self.assertIsNone(result) - - @mock.patch.object(os.path, 'isfile', autospec=True) - def test_retrieve_data_no_cache_file(self, mock_isfile): - mock_isfile.return_value = False - self.assertIsNone(filecache.retrieve_data(host='spam', port='eggs')) diff --git a/ironicclient/tests/unit/common/test_http.py b/ironicclient/tests/unit/common/test_http.py deleted file mode 100644 index 1a11a74..0000000 --- a/ironicclient/tests/unit/common/test_http.py +++ /dev/null @@ -1,788 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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 time - -import mock -from oslo_serialization import jsonutils -import requests -import six -from six.moves import http_client - -from keystoneauth1 import exceptions as kexc - -from ironicclient.common import filecache -from ironicclient.common import http -from ironicclient import exc -from ironicclient.tests.unit import utils - - -DEFAULT_TIMEOUT = 600 - -DEFAULT_HOST = 'localhost' -DEFAULT_PORT = '1234' - - -def _get_error_body(faultstring=None, debuginfo=None, description=None): - if description: - error_body = {'description': description} - else: - error_body = { - 'faultstring': faultstring, - 'debuginfo': debuginfo - } - raw_error_body = jsonutils.dump_as_bytes(error_body) - body = {'error_message': raw_error_body} - return jsonutils.dumps(body) - - -def _session_client(**kwargs): - return http.SessionClient(os_ironic_api_version='1.6', - api_version_select_state='default', - max_retries=5, - retry_interval=2, - auth=None, - interface='publicURL', - service_type='baremetal', - region_name='', - endpoint='http://%s:%s' % (DEFAULT_HOST, - DEFAULT_PORT), - **kwargs) - - -class VersionNegotiationMixinTest(utils.BaseTestCase): - - def setUp(self): - super(VersionNegotiationMixinTest, self).setUp() - self.test_object = http.VersionNegotiationMixin() - self.test_object.os_ironic_api_version = '1.6' - self.test_object.api_version_select_state = 'default' - self.test_object.endpoint = "http://localhost:1234" - self.mock_mcu = mock.MagicMock() - self.test_object._make_connection_url = self.mock_mcu - self.response = utils.FakeResponse( - {}, status=http_client.NOT_ACCEPTABLE) - self.test_object.get_server = mock.MagicMock( - return_value=('localhost', '1234')) - - def test__generic_parse_version_headers_has_headers(self): - response = {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': '1.6', - } - expected = ('1.1', '1.6') - result = self.test_object._generic_parse_version_headers(response.get) - self.assertEqual(expected, result) - - def test__generic_parse_version_headers_missing_headers(self): - response = {} - expected = (None, None) - result = self.test_object._generic_parse_version_headers(response.get) - self.assertEqual(expected, result) - - @mock.patch.object(filecache, 'save_data', autospec=True) - def test_negotiate_version_bad_state(self, mock_save_data): - # Test if bad api_version_select_state value - self.test_object.api_version_select_state = 'word of the day: augur' - self.assertRaises( - RuntimeError, - self.test_object.negotiate_version, - None, None) - self.assertEqual(0, mock_save_data.call_count) - - @mock.patch.object(filecache, 'save_data', autospec=True) - @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers', - autospec=True) - def test_negotiate_version_server_older(self, mock_pvh, mock_save_data): - # Test newer client and older server - latest_ver = '1.5' - mock_pvh.return_value = ('1.1', latest_ver) - mock_conn = mock.MagicMock() - result = self.test_object.negotiate_version(mock_conn, self.response) - self.assertEqual(latest_ver, result) - self.assertEqual(1, mock_pvh.call_count) - host, port = http.get_server(self.test_object.endpoint) - mock_save_data.assert_called_once_with(host=host, port=port, - data=latest_ver) - - @mock.patch.object(filecache, 'save_data', autospec=True) - @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers', - autospec=True) - def test_negotiate_version_server_newer(self, mock_pvh, mock_save_data): - # Test newer server and older client - mock_pvh.return_value = ('1.1', '1.10') - mock_conn = mock.MagicMock() - result = self.test_object.negotiate_version(mock_conn, self.response) - self.assertEqual('1.6', result) - self.assertEqual(1, mock_pvh.call_count) - mock_save_data.assert_called_once_with(host=DEFAULT_HOST, - port=DEFAULT_PORT, - data='1.6') - - @mock.patch.object(filecache, 'save_data', autospec=True) - @mock.patch.object(http.VersionNegotiationMixin, '_make_simple_request', - autospec=True) - @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers', - autospec=True) - def test_negotiate_version_server_no_version_on_error( - self, mock_pvh, mock_msr, mock_save_data): - # Test older Ironic version which errored with no version number and - # have to retry with simple get - mock_pvh.side_effect = iter([(None, None), ('1.1', '1.2')]) - mock_conn = mock.MagicMock() - result = self.test_object.negotiate_version(mock_conn, self.response) - self.assertEqual('1.2', result) - self.assertTrue(mock_msr.called) - self.assertEqual(2, mock_pvh.call_count) - self.assertEqual(1, mock_save_data.call_count) - - @mock.patch.object(filecache, 'save_data', autospec=True) - @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers', - autospec=True) - def test_negotiate_version_server_explicit_too_high(self, mock_pvh, - mock_save_data): - # requested version is not supported because it is too large - mock_pvh.return_value = ('1.1', '1.6') - mock_conn = mock.MagicMock() - self.test_object.api_version_select_state = 'user' - self.test_object.os_ironic_api_version = '99.99' - self.assertRaises( - exc.UnsupportedVersion, - self.test_object.negotiate_version, - mock_conn, self.response) - self.assertEqual(1, mock_pvh.call_count) - self.assertEqual(0, mock_save_data.call_count) - - @mock.patch.object(filecache, 'save_data', autospec=True) - @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers', - autospec=True) - def test_negotiate_version_server_explicit_not_supported(self, mock_pvh, - mock_save_data): - # requested version is supported by the server but the server returned - # 406 because the requested operation is not supported with the - # requested version - mock_pvh.return_value = ('1.1', '1.6') - mock_conn = mock.MagicMock() - self.test_object.api_version_select_state = 'negotiated' - self.test_object.os_ironic_api_version = '1.5' - self.assertRaises( - exc.UnsupportedVersion, - self.test_object.negotiate_version, - mock_conn, self.response) - self.assertEqual(1, mock_pvh.call_count) - self.assertEqual(0, mock_save_data.call_count) - - def test_get_server(self): - host = 'ironic-host' - port = '6385' - endpoint = 'http://%s:%s/ironic/v1/' % (host, port) - self.assertEqual((host, port), http.get_server(endpoint)) - - -class HttpClientTest(utils.BaseTestCase): - - def test_url_generation_trailing_slash_in_base(self): - client = http.HTTPClient('http://localhost/') - url = client._make_connection_url('/v1/resources') - self.assertEqual('http://localhost/v1/resources', url) - - def test_url_generation_without_trailing_slash_in_base(self): - client = http.HTTPClient('http://localhost') - url = client._make_connection_url('/v1/resources') - self.assertEqual('http://localhost/v1/resources', url) - - def test_url_generation_without_prefix_slash_in_path(self): - client = http.HTTPClient('http://localhost') - url = client._make_connection_url('v1/resources') - self.assertEqual('http://localhost/v1/resources', url) - - def test_server_https_request_with_application_octet_stream(self): - client = http.HTTPClient('https://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/octet-stream'}, - "Body", - version=1, - status_code=http_client.OK) - - response, body = client.json_request('GET', '/v1/resources') - self.assertEqual(client.session.request.return_value, response) - self.assertIsNone(body) - - def test_server_exception_empty_body(self): - error_body = _get_error_body() - client = http.HTTPClient('http://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, - version=1, - status_code=http_client.INTERNAL_SERVER_ERROR) - - self.assertRaises(exc.InternalServerError, - client.json_request, - 'GET', '/v1/resources') - - def test_server_exception_msg_only(self): - error_msg = 'test error msg' - error_body = _get_error_body(error_msg) - client = http.HTTPClient('http://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, - version=1, - status_code=http_client.INTERNAL_SERVER_ERROR) - - self.assertRaises(exc.InternalServerError, - client.json_request, - 'GET', '/v1/resources') - - def test_server_exception_description_only(self): - error_msg = 'test error msg' - error_body = _get_error_body(description=error_msg) - client = http.HTTPClient('http://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, - version=1, - status_code=http_client.BAD_REQUEST) - - self.assertRaisesRegex(exc.BadRequest, 'test error msg', - client.json_request, - 'GET', '/v1/resources') - - def test_server_https_request_ok(self): - client = http.HTTPClient('https://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - "Body", - version=1, - status_code=http_client.OK) - - client.json_request('GET', '/v1/resources') - - def test_server_https_empty_body(self): - error_body = _get_error_body() - - client = http.HTTPClient('https://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, - version=1, - status_code=http_client.INTERNAL_SERVER_ERROR) - - self.assertRaises(exc.InternalServerError, - client.json_request, - 'GET', '/v1/resources') - - def test_401_unauthorized_exception(self): - error_body = _get_error_body() - client = http.HTTPClient('http://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.UNAUTHORIZED) - - self.assertRaises(exc.Unauthorized, client.json_request, - 'GET', '/v1/resources') - - def test_http_request_not_valid_request(self): - client = http.HTTPClient('http://localhost/') - client.session.request = mock.Mock( - side_effect=http.requests.exceptions.InvalidSchema) - - self.assertRaises(exc.ValidationError, client._http_request, - 'http://localhost/', 'GET') - - def test__parse_version_headers(self): - # Test parsing of version headers from HTTPClient - error_body = _get_error_body() - expected_result = ('1.1', '1.6') - - client = http.HTTPClient('http://localhost/') - fake_resp = utils.mockSessionResponse( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': '1.6', - 'Content-Type': 'text/plain', - }, - error_body, - version=1, - status_code=http_client.NOT_ACCEPTABLE) - result = client._parse_version_headers(fake_resp) - self.assertEqual(expected_result, result) - - @mock.patch.object(filecache, 'save_data', autospec=True) - def test__http_request_client_fallback_fail(self, mock_save_data): - # Test when fallback to a supported version fails - host, port, latest_ver = 'localhost', '1234', '1.6' - error_body = _get_error_body() - - client = http.HTTPClient('http://%s:%s/' % (host, port)) - client.session = utils.mockSession( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': latest_ver, - 'content-type': 'text/plain', - }, - error_body, - version=1, - status_code=http_client.NOT_ACCEPTABLE) - self.assertRaises( - exc.UnsupportedVersion, - client._http_request, - '/v1/resources', - 'GET') - mock_save_data.assert_called_once_with(host=host, data=latest_ver, - port=port) - - @mock.patch.object(http.VersionNegotiationMixin, 'negotiate_version', - autospec=False) - def test__http_request_client_fallback_success(self, mock_negotiate): - # Test when fallback to a supported version succeeds - mock_negotiate.return_value = '1.6' - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': '1.6', - 'content-type': 'text/plain', - }, - error_body, - version=1, - status_code=http_client.NOT_ACCEPTABLE) - good_resp = utils.mockSessionResponse( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': '1.6', - 'content-type': 'text/plain', - }, - "We got some text", - version=1, - status_code=http_client.OK) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - - mock_session.request.side_effect = iter([bad_resp, good_resp]) - response, body_iter = client._http_request('/v1/resources', 'GET') - - self.assertEqual(http_client.OK, response.status_code) - self.assertEqual(1, mock_negotiate.call_count) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_curl_request_mask_password(self, mock_log): - client = http.HTTPClient('http://localhost/') - kwargs = {'headers': {'foo-header': 'bar-header'}, - 'body': '{"password": "foo"}'} - client.log_curl_request('foo', 'http://127.0.0.1', kwargs) - expected_log = ("curl -i -X foo -H 'foo-header: bar-header' " - "-d '{\"password\": \"***\"}' http://127.0.0.1") - mock_log.assert_called_once_with(expected_log) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_http_response_mask_password(self, mock_log): - client = http.HTTPClient('http://localhost/') - fake_response = utils.FakeResponse({}, version=1, reason='foo', - status=200) - body = '{"password": "foo"}' - client.log_http_response(fake_response, body=body) - expected_log = ("\nHTTP/0.1 200 foo\n\n{\"password\": \"***\"}\n") - mock_log.assert_called_once_with(expected_log) - - def test__https_init_ssl_args_insecure(self): - client = http.HTTPClient('https://localhost/', insecure=True) - - self.assertEqual(False, client.session.verify) - - def test__https_init_ssl_args_secure(self): - client = http.HTTPClient('https://localhost/', ca_file='test_ca', - key_file='test_key', cert_file='test_cert') - - self.assertEqual('test_ca', client.session.verify) - self.assertEqual(('test_cert', 'test_key'), client.session.cert) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_curl_request_with_body_and_header(self, mock_log): - client = http.HTTPClient('http://test') - headers = {'header1': 'value1'} - body = 'example body' - - client.log_curl_request('GET', '/v1/nodes', - {'headers': headers, 'body': body}) - - self.assertTrue(mock_log.called) - self.assertTrue(mock_log.call_args[0]) - self.assertEqual("curl -i -X GET -H 'header1: value1'" - " -d 'example body' http://test/v1/nodes", - mock_log.call_args[0][0]) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_curl_request_with_certs(self, mock_log): - headers = {'header1': 'value1'} - client = http.HTTPClient('https://test', key_file='key', - cert_file='cert', cacert='cacert', - token='fake-token') - - client.log_curl_request('GET', '/v1/test', {'headers': headers}) - - self.assertTrue(mock_log.called) - self.assertTrue(mock_log.call_args[0]) - - self.assertEqual("curl -i -X GET -H 'header1: value1' " - "--cert cert --key key https://test/v1/test", - mock_log.call_args[0][0]) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_curl_request_with_insecure_param(self, mock_log): - headers = {'header1': 'value1'} - http_client_object = http.HTTPClient('https://test', insecure=True, - token='fake-token') - - http_client_object.log_curl_request('GET', '/v1/test', - {'headers': headers}) - - self.assertTrue(mock_log.called) - self.assertTrue(mock_log.call_args[0]) - self.assertEqual("curl -i -X GET -H 'header1: value1' -k " - "--cert None --key None https://test/v1/test", - mock_log.call_args[0][0]) - - -class SessionClientTest(utils.BaseTestCase): - - def test_server_exception_empty_body(self): - error_body = _get_error_body() - - fake_session = utils.mockSession({'Content-Type': 'application/json'}, - error_body, - http_client.INTERNAL_SERVER_ERROR) - - client = _session_client(session=fake_session) - - self.assertRaises(exc.InternalServerError, - client.json_request, - 'GET', '/v1/resources') - - def test_server_exception_description_only(self): - error_msg = 'test error msg' - error_body = _get_error_body(description=error_msg) - fake_session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, status_code=http_client.BAD_REQUEST) - client = _session_client(session=fake_session) - - self.assertRaisesRegex(exc.BadRequest, 'test error msg', - client.json_request, - 'GET', '/v1/resources') - - def test__parse_version_headers(self): - # Test parsing of version headers from SessionClient - fake_session = utils.mockSession( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': '1.6', - 'content-type': 'text/plain', - }, - None, - http_client.HTTP_VERSION_NOT_SUPPORTED) - expected_result = ('1.1', '1.6') - client = _session_client(session=fake_session) - result = client._parse_version_headers(fake_session.request()) - self.assertEqual(expected_result, result) - - def _test_endpoint_override(self, endpoint): - fake_session = utils.mockSession({'content-type': 'application/json'}, - status_code=http_client.NO_CONTENT) - request_mock = mock.Mock() - fake_session.request = request_mock - request_mock.return_value = utils.mockSessionResponse( - headers={'content-type': 'application/json'}, - status_code=http_client.NO_CONTENT) - client = _session_client(session=fake_session, - endpoint_override=endpoint) - client.json_request('DELETE', '/v1/nodes/aa/maintenance') - expected_args_dict = { - 'headers': { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'X-OpenStack-Ironic-API-Version': '1.6' - }, - 'auth': None, 'user_agent': 'python-ironicclient', - 'endpoint_filter': { - 'interface': 'publicURL', - 'service_type': 'baremetal', - 'region_name': '' - } - } - if isinstance(endpoint, six.string_types): - trimmed = http._trim_endpoint_api_version(endpoint) - expected_args_dict['endpoint_override'] = trimmed - request_mock.assert_called_once_with( - '/v1/nodes/aa/maintenance', 'DELETE', raise_exc=False, - **expected_args_dict - ) - - def test_endpoint_override(self): - self._test_endpoint_override('http://1.0.0.1:6385') - - def test_endpoint_override_with_version(self): - self._test_endpoint_override('http://1.0.0.1:6385/v1') - - def test_endpoint_override_not_valid(self): - self._test_endpoint_override(True) - - -@mock.patch.object(time, 'sleep', lambda *_: None) -class RetriesTestCase(utils.BaseTestCase): - - def test_http_no_retry(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - client = http.HTTPClient('http://localhost/', max_retries=0) - - with mock.patch.object(client.session, 'request', autospec=True, - return_value=bad_resp) as mock_request: - - self.assertRaises(exc.Conflict, client._http_request, - '/v1/resources', 'GET') - self.assertEqual(1, mock_request.call_count) - - def test_http_retry(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - good_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - "meow", - version=1, - status_code=http_client.OK) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - - mock_session.request.side_effect = iter([bad_resp, good_resp]) - response, body_iter = client._http_request('/v1/resources', 'GET') - - self.assertEqual(http_client.OK, response.status_code) - self.assertEqual(2, mock_session.request.call_count) - - def test_http_retry_503(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.SERVICE_UNAVAILABLE) - good_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - "meow", - version=1, - status_code=http_client.OK) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.side_effect = iter([bad_resp, good_resp]) - response, body_iter = client._http_request('/v1/resources', 'GET') - - self.assertEqual(http_client.OK, response.status_code) - self.assertEqual(2, mock_session.request.call_count) - - def test_http_retry_connection_refused(self): - good_resp = utils.mockSessionResponse( - {'content-type': 'text/plain'}, - "meow", - version=1, - status_code=http_client.OK) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.side_effect = iter([exc.ConnectionRefused(), - good_resp]) - response, body_iter = client._http_request('/v1/resources', 'GET') - - self.assertEqual(http_client.OK, response.status_code) - self.assertEqual(2, mock_session.request.call_count) - - def test_http_failed_retry(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'content-type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.return_value = bad_resp - self.assertRaises(exc.Conflict, client._http_request, - '/v1/resources', 'GET') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 1, - mock_session.request.call_count) - - def test_http_max_retries_none(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'content-type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - client = http.HTTPClient('http://localhost/', max_retries=None) - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.return_value = bad_resp - self.assertRaises(exc.Conflict, client._http_request, - '/v1/resources', 'GET') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 1, - mock_session.request.call_count) - - def test_http_change_max_retries(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'content-type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - client = http.HTTPClient('http://localhost/', - max_retries=http.DEFAULT_MAX_RETRIES + 1) - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.return_value = bad_resp - self.assertRaises(exc.Conflict, client._http_request, - '/v1/resources', 'GET') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 2, - mock_session.request.call_count) - - def test_session_retry(self): - error_body = _get_error_body() - - fake_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - error_body, - http_client.CONFLICT) - ok_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - b"OK", - http_client.OK) - fake_session = mock.Mock(spec=requests.Session) - fake_session.request.side_effect = iter((fake_resp, ok_resp)) - - client = _session_client(session=fake_session) - client.json_request('GET', '/v1/resources') - self.assertEqual(2, fake_session.request.call_count) - - def test_session_retry_503(self): - error_body = _get_error_body() - - fake_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - error_body, - http_client.SERVICE_UNAVAILABLE) - ok_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - b"OK", - http_client.OK) - fake_session = mock.Mock(spec=requests.Session) - fake_session.request.side_effect = iter((fake_resp, ok_resp)) - - client = _session_client(session=fake_session) - client.json_request('GET', '/v1/resources') - self.assertEqual(2, fake_session.request.call_count) - - def test_session_retry_connection_refused(self): - ok_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - b"OK", - http_client.OK) - fake_session = mock.Mock(spec=requests.Session) - fake_session.request.side_effect = iter((exc.ConnectionRefused(), - ok_resp)) - - client = _session_client(session=fake_session) - client.json_request('GET', '/v1/resources') - self.assertEqual(2, fake_session.request.call_count) - - def test_session_retry_retriable_connection_failure(self): - ok_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - b"OK", - http_client.OK) - fake_session = mock.Mock(spec=requests.Session) - fake_session.request.side_effect = iter( - (kexc.RetriableConnectionFailure(), ok_resp)) - - client = _session_client(session=fake_session) - client.json_request('GET', '/v1/resources') - self.assertEqual(2, fake_session.request.call_count) - - def test_session_retry_fail(self): - error_body = _get_error_body() - - fake_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - error_body, - http_client.CONFLICT) - fake_session = mock.Mock(spec=requests.Session) - fake_session.request.return_value = fake_resp - - client = _session_client(session=fake_session) - - self.assertRaises(exc.Conflict, client.json_request, - 'GET', '/v1/resources') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 1, - fake_session.request.call_count) - - def test_session_max_retries_none(self): - error_body = _get_error_body() - - fake_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - error_body, - http_client.CONFLICT) - fake_session = mock.Mock(spec=requests.Session) - fake_session.request.return_value = fake_resp - - client = _session_client(session=fake_session) - client.conflict_max_retries = None - - self.assertRaises(exc.Conflict, client.json_request, - 'GET', '/v1/resources') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 1, - fake_session.request.call_count) - - def test_session_change_max_retries(self): - error_body = _get_error_body() - - fake_resp = utils.mockSessionResponse( - {'Content-Type': 'application/json'}, - error_body, - http_client.CONFLICT) - fake_session = mock.Mock(spec=requests.Session) - fake_session.request.return_value = fake_resp - - client = _session_client(session=fake_session) - client.conflict_max_retries = http.DEFAULT_MAX_RETRIES + 1 - - self.assertRaises(exc.Conflict, client.json_request, - 'GET', '/v1/resources') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 2, - fake_session.request.call_count) diff --git a/ironicclient/tests/unit/common/test_utils.py b/ironicclient/tests/unit/common/test_utils.py deleted file mode 100644 index ffc31bb..0000000 --- a/ironicclient/tests/unit/common/test_utils.py +++ /dev/null @@ -1,371 +0,0 @@ -# Copyright 2013 OpenStack LLC. -# 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 os -import subprocess -import sys -import tempfile - -import mock -import six.moves.builtins as __builtin__ - -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.tests.unit import utils as test_utils - - -class UtilsTest(test_utils.BaseTestCase): - - def test_key_value_pairs_to_dict(self): - kv_list = ['str=foo', 'int=1', 'bool=true', - 'list=[1, 2, 3]', 'dict={"foo": "bar"}'] - - d = utils.key_value_pairs_to_dict(kv_list) - self.assertEqual( - {'str': 'foo', 'int': 1, 'bool': True, - 'list': [1, 2, 3], 'dict': {'foo': 'bar'}}, - d) - - def test_key_value_pairs_to_dict_nothing(self): - self.assertEqual({}, utils.key_value_pairs_to_dict(None)) - self.assertEqual({}, utils.key_value_pairs_to_dict([])) - - def test_args_array_to_dict(self): - my_args = { - 'matching_metadata': ['str=foo', 'int=1', 'bool=true', - 'list=[1, 2, 3]', 'dict={"foo": "bar"}'], - 'other': 'value' - } - cleaned_dict = utils.args_array_to_dict(my_args, - "matching_metadata") - self.assertEqual({ - 'matching_metadata': {'str': 'foo', 'int': 1, 'bool': True, - 'list': [1, 2, 3], 'dict': {'foo': 'bar'}}, - 'other': 'value' - }, cleaned_dict) - - def test_args_array_to_patch(self): - my_args = { - 'attributes': ['str=foo', 'int=1', 'bool=true', - 'list=[1, 2, 3]', 'dict={"foo": "bar"}'], - 'op': 'add', - } - patch = utils.args_array_to_patch(my_args['op'], - my_args['attributes']) - self.assertEqual([{'op': 'add', 'value': 'foo', 'path': '/str'}, - {'op': 'add', 'value': 1, 'path': '/int'}, - {'op': 'add', 'value': True, 'path': '/bool'}, - {'op': 'add', 'value': [1, 2, 3], 'path': '/list'}, - {'op': 'add', 'value': {"foo": "bar"}, - 'path': '/dict'}], patch) - - def test_args_array_to_patch_format_error(self): - my_args = { - 'attributes': ['foobar'], - 'op': 'add', - } - self.assertRaises(exc.CommandError, utils.args_array_to_patch, - my_args['op'], my_args['attributes']) - - def test_args_array_to_patch_remove(self): - my_args = { - 'attributes': ['/foo', 'extra/bar'], - 'op': 'remove', - } - patch = utils.args_array_to_patch(my_args['op'], - my_args['attributes']) - self.assertEqual([{'op': 'remove', 'path': '/foo'}, - {'op': 'remove', 'path': '/extra/bar'}], patch) - - def test_split_and_deserialize(self): - ret = utils.split_and_deserialize('str=foo') - self.assertEqual(('str', 'foo'), ret) - - ret = utils.split_and_deserialize('int=1') - self.assertEqual(('int', 1), ret) - - ret = utils.split_and_deserialize('bool=false') - self.assertEqual(('bool', False), ret) - - ret = utils.split_and_deserialize('list=[1, "foo", 2]') - self.assertEqual(('list', [1, "foo", 2]), ret) - - ret = utils.split_and_deserialize('dict={"foo": 1}') - self.assertEqual(('dict', {"foo": 1}), ret) - - ret = utils.split_and_deserialize('str_int="1"') - self.assertEqual(('str_int', "1"), ret) - - def test_split_and_deserialize_fail(self): - self.assertRaises(exc.CommandError, - utils.split_and_deserialize, 'foo:bar') - - def test_bool_arg_value(self): - self.assertTrue(utils.bool_argument_value('arg', 'y', strict=True)) - self.assertTrue(utils.bool_argument_value('arg', 'TrUe', strict=True)) - self.assertTrue(utils.bool_argument_value('arg', '1', strict=True)) - self.assertTrue(utils.bool_argument_value('arg', 1, strict=True)) - - self.assertFalse(utils.bool_argument_value('arg', '0', strict=True)) - self.assertFalse(utils.bool_argument_value('arg', 'No', strict=True)) - - self.assertRaises(exc.CommandError, - utils.bool_argument_value, 'arg', 'ee', strict=True) - - self.assertFalse(utils.bool_argument_value('arg', 'ee', strict=False)) - self.assertTrue(utils.bool_argument_value('arg', 'ee', strict=False, - default=True)) - # No check that default is a Boolean... - self.assertEqual('foo', utils.bool_argument_value('arg', 'ee', - strict=False, default='foo')) - - def test_check_for_invalid_fields(self): - self.assertIsNone(utils.check_for_invalid_fields( - ['a', 'b'], ['a', 'b', 'c'])) - # 'd' is not a valid field - self.assertRaises(exc.CommandError, utils.check_for_invalid_fields, - ['a', 'd'], ['a', 'b', 'c']) - - def test_convert_list_props_to_comma_separated_strings(self): - data = {'prop1': 'val1', - 'prop2': ['item1', 'item2', 'item3']} - result = utils.convert_list_props_to_comma_separated(data) - self.assertEqual('val1', result['prop1']) - self.assertEqual('item1, item2, item3', result['prop2']) - - def test_convert_list_props_to_comma_separated_mix(self): - data = {'prop1': 'val1', - 'prop2': [1, 2.5, 'item3']} - result = utils.convert_list_props_to_comma_separated(data) - self.assertEqual('val1', result['prop1']) - self.assertEqual('1, 2.5, item3', result['prop2']) - - def test_convert_list_props_to_comma_separated_partial(self): - data = {'prop1': [1, 2, 3], - 'prop2': [1, 2.5, 'item3']} - result = utils.convert_list_props_to_comma_separated( - data, props=['prop2']) - self.assertEqual([1, 2, 3], result['prop1']) - self.assertEqual('1, 2.5, item3', result['prop2']) - - -class CommonParamsForListTest(test_utils.BaseTestCase): - def setUp(self): - super(CommonParamsForListTest, self).setUp() - self.args = mock.Mock(marker=None, limit=None, sort_key=None, - sort_dir=None, detail=False, fields=None, - spec=True) - self.expected_params = {'detail': False} - - def test_nothing_set(self): - self.assertEqual(self.expected_params, - utils.common_params_for_list(self.args, [], [])) - - def test_marker_and_limit(self): - self.args.marker = 'foo' - self.args.limit = 42 - self.expected_params.update({'marker': 'foo', 'limit': 42}) - self.assertEqual(self.expected_params, - utils.common_params_for_list(self.args, [], [])) - - def test_invalid_limit(self): - self.args.limit = -42 - self.assertRaises(exc.CommandError, - utils.common_params_for_list, - self.args, [], []) - - def test_sort_key_and_sort_dir(self): - self.args.sort_key = 'field' - self.args.sort_dir = 'desc' - self.expected_params.update({'sort_key': 'field', 'sort_dir': 'desc'}) - self.assertEqual(self.expected_params, - utils.common_params_for_list(self.args, - ['field'], - [])) - - def test_sort_key_allows_label(self): - self.args.sort_key = 'Label' - self.expected_params.update({'sort_key': 'field'}) - self.assertEqual(self.expected_params, - utils.common_params_for_list(self.args, - ['field', 'field2'], - ['Label', 'Label2'])) - - def test_sort_key_invalid(self): - self.args.sort_key = 'something' - self.assertRaises(exc.CommandError, - utils.common_params_for_list, - self.args, - ['field', 'field2'], - []) - - def test_sort_dir_invalid(self): - self.args.sort_dir = 'something' - self.assertRaises(exc.CommandError, - utils.common_params_for_list, - self.args, - [], - []) - - def test_detail(self): - self.args.detail = True - self.expected_params['detail'] = True - self.assertEqual(self.expected_params, - utils.common_params_for_list(self.args, [], [])) - - def test_fields(self): - self.args.fields = [['a', 'b', 'c']] - self.expected_params.update({'fields': ['a', 'b', 'c']}) - self.assertEqual(self.expected_params, - utils.common_params_for_list(self.args, [], [])) - - -class CommonFiltersTest(test_utils.BaseTestCase): - def test_limit(self): - result = utils.common_filters(limit=42) - self.assertEqual(['limit=42'], result) - - def test_limit_0(self): - result = utils.common_filters(limit=0) - self.assertEqual([], result) - - def test_other(self): - for key in ('marker', 'sort_key', 'sort_dir'): - result = utils.common_filters(**{key: 'test'}) - self.assertEqual(['%s=test' % key], result) - - def test_fields(self): - result = utils.common_filters(fields=['a', 'b', 'c']) - self.assertEqual(['fields=a,b,c'], result) - - -@mock.patch.object(subprocess, 'Popen', autospec=True) -class MakeConfigDriveTest(test_utils.BaseTestCase): - - def setUp(self): - super(MakeConfigDriveTest, self).setUp() - # expected genisoimage cmd - self.genisoimage_cmd = ['genisoimage', '-o', mock.ANY, - '-ldots', '-allow-lowercase', - '-allow-multidot', '-l', - '-publisher', 'ironicclient-configdrive 0.1', - '-quiet', '-J', '-r', '-V', - 'config-2', mock.ANY] - - def test_make_configdrive(self, mock_popen): - fake_process = mock.Mock(returncode=0) - fake_process.communicate.return_value = ('', '') - mock_popen.return_value = fake_process - - with utils.tempdir() as dirname: - utils.make_configdrive(dirname) - - mock_popen.assert_called_once_with(self.genisoimage_cmd, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - fake_process.communicate.assert_called_once_with() - - @mock.patch.object(os, 'access', autospec=True) - def test_make_configdrive_non_readable_dir(self, mock_access, mock_popen): - mock_access.return_value = False - self.assertRaises(exc.CommandError, utils.make_configdrive, 'fake-dir') - mock_access.assert_called_once_with('fake-dir', os.R_OK) - self.assertFalse(mock_popen.called) - - @mock.patch.object(os, 'access', autospec=True) - def test_make_configdrive_oserror(self, mock_access, mock_popen): - mock_access.return_value = True - mock_popen.side_effect = OSError('boom') - - self.assertRaises(exc.CommandError, utils.make_configdrive, 'fake-dir') - mock_access.assert_called_once_with('fake-dir', os.R_OK) - mock_popen.assert_called_once_with(self.genisoimage_cmd, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - - @mock.patch.object(os, 'access', autospec=True) - def test_make_configdrive_non_zero_returncode(self, mock_access, - mock_popen): - fake_process = mock.Mock(returncode=123) - fake_process.communicate.return_value = ('', '') - mock_popen.return_value = fake_process - - self.assertRaises(exc.CommandError, utils.make_configdrive, 'fake-dir') - mock_access.assert_called_once_with('fake-dir', os.R_OK) - mock_popen.assert_called_once_with(self.genisoimage_cmd, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - fake_process.communicate.assert_called_once_with() - - -class GetFromStdinTest(test_utils.BaseTestCase): - - @mock.patch.object(sys, 'stdin', autospec=True) - def test_get_from_stdin(self, mock_stdin): - contents = '[{"step": "upgrade", "interface": "deploy"}]' - mock_stdin.read.return_value = contents - desc = 'something' - - info = utils.get_from_stdin(desc) - self.assertEqual(info, contents) - mock_stdin.read.assert_called_once_with() - - @mock.patch.object(sys, 'stdin', autospec=True) - def test_get_from_stdin_fail(self, mock_stdin): - mock_stdin.read.side_effect = IOError - desc = 'something' - - self.assertRaises(exc.InvalidAttribute, utils.get_from_stdin, desc) - mock_stdin.read.assert_called_once_with() - - -class HandleJsonFileTest(test_utils.BaseTestCase): - - def test_handle_json_or_file_arg(self): - cleansteps = '[{"step": "upgrade", "interface": "deploy"}]' - steps = utils.handle_json_or_file_arg(cleansteps) - self.assertEqual(json.loads(cleansteps), steps) - - def test_handle_json_or_file_arg_bad_json(self): - cleansteps = 'foo' - self.assertRaisesRegex(exc.InvalidAttribute, - 'For JSON', - utils.handle_json_or_file_arg, cleansteps) - - def test_handle_json_or_file_arg_file(self): - contents = '[{"step": "upgrade", "interface": "deploy"}]' - - with tempfile.NamedTemporaryFile(mode='w') as f: - f.write(contents) - f.flush() - steps = utils.handle_json_or_file_arg(f.name) - - self.assertEqual(json.loads(contents), steps) - - @mock.patch.object(__builtin__, 'open', autospec=True) - def test_handle_json_or_file_arg_file_fail(self, mock_open): - mock_file_object = mock.MagicMock() - mock_file_handle = mock.MagicMock() - mock_file_handle.__enter__.return_value = mock_file_object - mock_open.return_value = mock_file_handle - mock_file_object.read.side_effect = IOError - - with tempfile.NamedTemporaryFile(mode='w') as f: - self.assertRaisesRegex(exc.InvalidAttribute, - "from file", - utils.handle_json_or_file_arg, f.name) - mock_open.assert_called_once_with(f.name, 'r') - mock_file_object.read.assert_called_once_with() diff --git a/ironicclient/tests/unit/osc/__init__.py b/ironicclient/tests/unit/osc/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/unit/osc/fakes.py b/ironicclient/tests/unit/osc/fakes.py deleted file mode 100644 index cd9731b..0000000 --- a/ironicclient/tests/unit/osc/fakes.py +++ /dev/null @@ -1,60 +0,0 @@ -# -# Copyright 2015 Red Hat, Inc. -# -# 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 sys - - -AUTH_TOKEN = "foobar" -AUTH_URL = "http://0.0.0.0" - - -class FakeApp(object): - def __init__(self): - _stdout = None - self.client_manager = None - self.stdin = sys.stdin - self.stdout = _stdout or sys.stdout - self.stderr = sys.stderr - self.restapi = None - - -class FakeClientManager(object): - def __init__(self): - self.identity = None - self.auth_ref = None - self.interface = 'public' - self._region_name = 'RegionOne' - self.session = 'fake session' - self._api_version = {'baremetal': '1.6'} - - -class FakeResource(object): - def __init__(self, manager, info, loaded=False): - self.__name__ = type(self).__name__ - self.manager = manager - self._info = info - self._add_details(info) - self._loaded = loaded - - def _add_details(self, info): - for (k, v) in info.items(): - setattr(self, k, v) - - def __repr__(self): - reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and - k != 'manager') - info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) - return "<%s %s>" % (self.__class__.__name__, info) diff --git a/ironicclient/tests/unit/osc/test_plugin.py b/ironicclient/tests/unit/osc/test_plugin.py deleted file mode 100644 index a687d47..0000000 --- a/ironicclient/tests/unit/osc/test_plugin.py +++ /dev/null @@ -1,110 +0,0 @@ -# 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 argparse - -import mock -import testtools - -from ironicclient.common import http -from ironicclient.osc import plugin -from ironicclient.tests.unit.osc import fakes -from ironicclient.v1 import client - - -class MakeClientTest(testtools.TestCase): - - @mock.patch.object(plugin, 'OS_BAREMETAL_API_VERSION_SPECIFIED', new=True) - @mock.patch.object(plugin.LOG, 'warning', autospec=True) - @mock.patch.object(client, 'Client', autospec=True) - def test_make_client(self, mock_client, mock_warning): - instance = fakes.FakeClientManager() - instance.get_endpoint_for_service_type = mock.Mock( - return_value='endpoint') - plugin.make_client(instance) - mock_client.assert_called_once_with(os_ironic_api_version='1.6', - session=instance.session, - region_name=instance._region_name, - endpoint='endpoint') - self.assertFalse(mock_warning.called) - instance.get_endpoint_for_service_type.assert_called_once_with( - 'baremetal', region_name=instance._region_name, - interface=instance.interface) - - @mock.patch.object(plugin, 'OS_BAREMETAL_API_VERSION_SPECIFIED', new=False) - @mock.patch.object(plugin.LOG, 'warning', autospec=True) - @mock.patch.object(client, 'Client', autospec=True) - def test_make_client_log_warning_no_version_specified(self, mock_client, - mock_warning): - instance = fakes.FakeClientManager() - instance.get_endpoint_for_service_type = mock.Mock( - return_value='endpoint') - instance._api_version = {'baremetal': http.DEFAULT_VER} - plugin.make_client(instance) - mock_client.assert_called_once_with( - os_ironic_api_version=http.DEFAULT_VER, - session=instance.session, - region_name=instance._region_name, - endpoint='endpoint') - self.assertTrue(mock_warning.called) - instance.get_endpoint_for_service_type.assert_called_once_with( - 'baremetal', region_name=instance._region_name, - interface=instance.interface) - - @mock.patch.object(plugin.utils, 'env', lambda x: '1.29') - @mock.patch.object(plugin, 'OS_BAREMETAL_API_VERSION_SPECIFIED', new=False) - @mock.patch.object(plugin.LOG, 'warning', autospec=True) - @mock.patch.object(client, 'Client', autospec=True) - def test_make_client_version_from_env_no_warning(self, mock_client, - mock_warning): - instance = fakes.FakeClientManager() - instance.get_endpoint_for_service_type = mock.Mock( - return_value='endpoint') - plugin.make_client(instance) - self.assertFalse(mock_warning.called) - - -class BuildOptionParserTest(testtools.TestCase): - - @mock.patch.object(argparse.ArgumentParser, 'add_argument') - def test_build_option_parser(self, mock_add_argument): - parser = argparse.ArgumentParser() - mock_add_argument.reset_mock() - plugin.build_option_parser(parser) - version_list = ['1'] + ['1.%d' % i for i in range( - 1, plugin.LAST_KNOWN_API_VERSION + 1)] + ['latest'] - mock_add_argument.assert_called_once_with( - '--os-baremetal-api-version', action=plugin.ReplaceLatestVersion, - choices=version_list, default=http.DEFAULT_VER, help=mock.ANY, - metavar='') - - -class ReplaceLatestVersionTest(testtools.TestCase): - - def test___call___latest(self): - parser = argparse.ArgumentParser() - plugin.build_option_parser(parser) - namespace = argparse.Namespace() - parser.parse_known_args(['--os-baremetal-api-version', 'latest'], - namespace) - self.assertEqual('1.%d' % plugin.LAST_KNOWN_API_VERSION, - namespace.os_baremetal_api_version) - self.assertTrue(plugin.OS_BAREMETAL_API_VERSION_SPECIFIED) - - def test___call___specific_version(self): - parser = argparse.ArgumentParser() - plugin.build_option_parser(parser) - namespace = argparse.Namespace() - parser.parse_known_args(['--os-baremetal-api-version', '1.4'], - namespace) - self.assertEqual('1.4', namespace.os_baremetal_api_version) - self.assertTrue(plugin.OS_BAREMETAL_API_VERSION_SPECIFIED) diff --git a/ironicclient/tests/unit/osc/v1/__init__.py b/ironicclient/tests/unit/osc/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/unit/osc/v1/fakes.py b/ironicclient/tests/unit/osc/v1/fakes.py deleted file mode 100644 index faa479a..0000000 --- a/ironicclient/tests/unit/osc/v1/fakes.py +++ /dev/null @@ -1,185 +0,0 @@ -# -# Copyright 2015 Red Hat, Inc. -# -# 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 mock -from osc_lib.tests import utils - -from ironicclient.tests.unit.osc import fakes - -baremetal_chassis_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' -baremetal_chassis_uuid_empty = '' -baremetal_properties_empty = '' -baremetal_chassis_description = 'chassis description' -baremetal_chassis_extra = {} -BAREMETAL_CHASSIS = { - 'uuid': baremetal_chassis_uuid, - 'description': baremetal_chassis_description, - 'extra': baremetal_chassis_extra, -} - -baremetal_uuid = 'xxx-xxxxxx-xxxx' -baremetal_name = 'fake name' -baremetal_instance_uuid = 'yyy-yyyyyy-yyyy' -baremetal_power_state = None -baremetal_provision_state = None -baremetal_maintenance = False - -BAREMETAL = { - 'uuid': baremetal_uuid, - 'name': baremetal_name, - 'instance_uuid': baremetal_instance_uuid, - 'power_state': baremetal_power_state, - 'provision_state': baremetal_provision_state, - 'maintenance': baremetal_maintenance, - 'links': [], - 'volume': [], -} - -baremetal_port_uuid = 'zzz-zzzzzz-zzzz' -baremetal_port_address = 'AA:BB:CC:DD:EE:FF' -baremetal_port_extra = {'key1': 'value1', - 'key2': 'value2'} -baremetal_port_physical_network = 'physnet1' - -BAREMETAL_PORT = { - 'uuid': baremetal_port_uuid, - 'address': baremetal_port_address, - 'extra': baremetal_port_extra, - 'node_uuid': baremetal_uuid, -} - -baremetal_driver_hosts = ['fake-host1', 'fake-host2'] -baremetal_driver_name = 'fakedrivername' -baremetal_driver_type = 'classic' -baremetal_driver_default_boot_if = 'boot' -baremetal_driver_default_console_if = 'console' -baremetal_driver_default_deploy_if = 'deploy' -baremetal_driver_default_inspect_if = 'inspect' -baremetal_driver_default_management_if = 'management' -baremetal_driver_default_network_if = 'network' -baremetal_driver_default_power_if = 'power' -baremetal_driver_default_raid_if = 'raid' -baremetal_driver_default_storage_if = 'storage' -baremetal_driver_default_vendor_if = 'vendor' -baremetal_driver_enabled_boot_ifs = ['boot', 'boot2'] -baremetal_driver_enabled_console_ifs = ['console', 'console2'] -baremetal_driver_enabled_deploy_ifs = ['deploy', 'deploy2'] -baremetal_driver_enabled_inspect_ifs = ['inspect', 'inspect2'] -baremetal_driver_enabled_management_ifs = ['management', 'management2'] -baremetal_driver_enabled_network_ifs = ['network', 'network2'] -baremetal_driver_enabled_power_ifs = ['power', 'power2'] -baremetal_driver_enabled_raid_ifs = ['raid', 'raid2'] -baremetal_driver_enabled_storage_ifs = ['storage', 'storage2'] -baremetal_driver_enabled_vendor_ifs = ['vendor', 'vendor2'] - -BAREMETAL_DRIVER = { - 'hosts': baremetal_driver_hosts, - 'name': baremetal_driver_name, - 'type': baremetal_driver_type, - 'default_boot_interface': baremetal_driver_default_boot_if, - 'default_console_interface': baremetal_driver_default_console_if, - 'default_deploy_interface': baremetal_driver_default_deploy_if, - 'default_inspect_interface': baremetal_driver_default_inspect_if, - 'default_management_interface': baremetal_driver_default_management_if, - 'default_network_interface': baremetal_driver_default_network_if, - 'default_power_interface': baremetal_driver_default_power_if, - 'default_raid_interface': baremetal_driver_default_raid_if, - 'default_storage_interface': baremetal_driver_default_storage_if, - 'default_vendor_interface': baremetal_driver_default_vendor_if, - 'enabled_boot_interfaces': baremetal_driver_enabled_boot_ifs, - 'enabled_console_interfaces': baremetal_driver_enabled_console_ifs, - 'enabled_deploy_interfaces': baremetal_driver_enabled_deploy_ifs, - 'enabled_inspect_interfaces': baremetal_driver_enabled_inspect_ifs, - 'enabled_management_interfaces': baremetal_driver_enabled_management_ifs, - 'enabled_network_interfaces': baremetal_driver_enabled_network_ifs, - 'enabled_power_interfaces': baremetal_driver_enabled_power_ifs, - 'enabled_raid_interfaces': baremetal_driver_enabled_raid_ifs, - 'enabled_storage_interfaces': baremetal_driver_enabled_storage_ifs, - 'enabled_vendor_interfaces': baremetal_driver_enabled_vendor_ifs, -} - -baremetal_driver_passthru_method = 'lookup' - -BAREMETAL_DRIVER_PASSTHRU = {"lookup": {"attach": "false", - "http_methods": ["POST"], - "description": "", - "async": "false"}} - -baremetal_portgroup_uuid = 'ppp-gggggg-pppp' -baremetal_portgroup_name = 'Portgroup-name' -baremetal_portgroup_address = 'AA:BB:CC:CC:BB:AA' -baremetal_portgroup_mode = 'active-backup' -baremetal_portgroup_extra = {'key1': 'value1', - 'key2': 'value2'} -baremetal_portgroup_properties = {'key1': 'value11', - 'key2': 'value22'} - -PORTGROUP = {'uuid': baremetal_portgroup_uuid, - 'name': baremetal_portgroup_name, - 'node_uuid': baremetal_uuid, - 'address': baremetal_portgroup_address, - 'extra': baremetal_portgroup_extra, - 'mode': baremetal_portgroup_mode, - 'properties': baremetal_portgroup_properties, - } - -VIFS = {'vifs': [{'id': 'aaa-aa'}]} - -baremetal_volume_connector_uuid = 'vvv-cccccc-vvvv' -baremetal_volume_connector_type = 'iqn' -baremetal_volume_connector_connector_id = 'iqn.2017-01.connector' -baremetal_volume_connector_extra = {'key1': 'value1', - 'key2': 'value2'} -VOLUME_CONNECTOR = { - 'uuid': baremetal_volume_connector_uuid, - 'node_uuid': baremetal_uuid, - 'type': baremetal_volume_connector_type, - 'connector_id': baremetal_volume_connector_connector_id, - 'extra': baremetal_volume_connector_extra, -} - -baremetal_volume_target_uuid = 'vvv-tttttt-vvvv' -baremetal_volume_target_volume_type = 'iscsi' -baremetal_volume_target_boot_index = 0 -baremetal_volume_target_volume_id = 'vvv-tttttt-iii' -baremetal_volume_target_extra = {'key1': 'value1', - 'key2': 'value2'} -baremetal_volume_target_properties = {'key11': 'value11', - 'key22': 'value22'} -VOLUME_TARGET = { - 'uuid': baremetal_volume_target_uuid, - 'node_uuid': baremetal_uuid, - 'volume_type': baremetal_volume_target_volume_type, - 'boot_index': baremetal_volume_target_boot_index, - 'volume_id': baremetal_volume_target_volume_id, - 'extra': baremetal_volume_target_extra, - 'properties': baremetal_volume_target_properties, -} - - -class TestBaremetal(utils.TestCommand): - - def setUp(self): - super(TestBaremetal, self).setUp() - - self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN") - self.app.client_manager.baremetal = mock.Mock() - - -class FakeBaremetalResource(fakes.FakeResource): - - def get_keys(self): - return {'property': 'value'} diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_chassis.py b/ironicclient/tests/unit/osc/v1/test_baremetal_chassis.py deleted file mode 100644 index e067961..0000000 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_chassis.py +++ /dev/null @@ -1,591 +0,0 @@ -# -# Copyright 2016 Intel Corporation -# -# 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 copy -import mock - -from osc_lib.tests import utils as oscutils - -from ironicclient import exc -from ironicclient.osc.v1 import baremetal_chassis -from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes - - -class TestChassis(baremetal_fakes.TestBaremetal): - - def setUp(self): - super(TestChassis, self).setUp() - - # Get a shortcut to the baremetal manager mock - self.baremetal_mock = self.app.client_manager.baremetal - self.baremetal_mock.reset_mock() - - -class TestChassisCreate(TestChassis): - def setUp(self): - super(TestChassisCreate, self).setUp() - - self.baremetal_mock.chassis.create.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_CHASSIS), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_chassis.CreateBaremetalChassis(self.app, None) - self.arglist = [] - self.verifylist = [] - self.collist = ( - 'description', - 'extra', - 'uuid', - ) - self.datalist = ( - baremetal_fakes.baremetal_chassis_description, - baremetal_fakes.baremetal_chassis_extra, - baremetal_fakes.baremetal_chassis_uuid, - ) - self.actual_kwargs = {} - - def check_with_options(self, addl_arglist, addl_verifylist, addl_kwargs): - arglist = copy.copy(self.arglist) + addl_arglist - verifylist = copy.copy(self.verifylist) + addl_verifylist - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - collist = copy.copy(self.collist) - self.assertEqual(collist, columns) - self.assertNotIn('nodes', columns) - - datalist = copy.copy(self.datalist) - self.assertEqual(datalist, tuple(data)) - - kwargs = copy.copy(self.actual_kwargs) - kwargs.update(addl_kwargs) - - self.baremetal_mock.chassis.create.assert_called_once_with(**kwargs) - - def test_chassis_create_no_options(self): - self.check_with_options([], [], {}) - - def test_chassis_create_with_description(self): - description = 'chassis description' - self.check_with_options(['--description', description], - [('description', description)], - {'description': description}) - - def test_chassis_create_with_extra(self): - extra1 = 'arg1=val1' - extra2 = 'arg2=val2' - self.check_with_options(['--extra', extra1, - '--extra', extra2], - [('extra', [extra1, extra2])], - {'extra': { - 'arg1': 'val1', - 'arg2': 'val2'}}) - - def test_chassis_create_with_uuid(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - self.check_with_options(['--uuid', uuid], - [('uuid', uuid)], - {'uuid': uuid}) - - -class TestChassisDelete(TestChassis): - def setUp(self): - super(TestChassisDelete, self).setUp() - - self.baremetal_mock.chassis.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_CHASSIS), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_chassis.DeleteBaremetalChassis(self.app, None) - - def test_chassis_delete(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [uuid] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.chassis.delete.assert_called_with(uuid) - - def test_chassis_delete_multiple(self): - uuid1 = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' - uuid2 = '11111111-2222-3333-4444-555555555555' - arglist = [uuid1, uuid2] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - args = [uuid1, uuid2] - self.baremetal_mock.chassis.delete.has_calls( - [mock.call(x) for x in args] - ) - self.assertEqual(2, self.baremetal_mock.chassis.delete.call_count) - - def test_chassis_delete_multiple_with_failure(self): - uuid1 = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' - uuid2 = '11111111-2222-3333-4444-555555555555' - arglist = [uuid1, uuid2] - verifylist = [] - - self.baremetal_mock.chassis.delete.side_effect = [ - '', exc.ClientException] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.assertRaises(exc.ClientException, - self.cmd.take_action, - parsed_args) - - # Set expected values - args = [uuid1, uuid2] - self.baremetal_mock.chassis.delete.has_calls( - [mock.call(x) for x in args] - ) - self.assertEqual(2, self.baremetal_mock.chassis.delete.call_count) - - -class TestChassisList(TestChassis): - - def setUp(self): - super(TestChassisList, self).setUp() - - self.baremetal_mock.chassis.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_CHASSIS), - loaded=True, - ), - ] - - # Get the command object to test - self.cmd = baremetal_chassis.ListBaremetalChassis(self.app, None) - - def test_chassis_list_no_options(self): - arglist = [] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - } - - self.baremetal_mock.chassis.list.assert_called_with( - **kwargs - ) - - collist = ( - "UUID", - "Description", - ) - self.assertEqual(collist, columns) - datalist = (( - baremetal_fakes.baremetal_chassis_uuid, - baremetal_fakes.baremetal_chassis_description, - ), ) - self.assertEqual(datalist, tuple(data)) - - def test_chassis_list_long(self): - arglist = [ - '--long', - ] - verifylist = [ - ('long', True), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'detail': True, - 'marker': None, - 'limit': None, - } - - self.baremetal_mock.chassis.list.assert_called_with( - **kwargs - ) - - collist = ('UUID', 'Description', 'Created At', 'Updated At', 'Extra') - self.assertEqual(collist, columns) - datalist = (( - baremetal_fakes.baremetal_chassis_uuid, - baremetal_fakes.baremetal_chassis_description, - '', - '', - baremetal_fakes.baremetal_chassis_extra, - ), ) - self.assertEqual(datalist, tuple(data)) - - def test_chassis_list_fields(self): - arglist = [ - '--fields', 'uuid', 'extra', - ] - verifylist = [ - ('fields', [['uuid', 'extra']]), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'detail': False, - 'fields': ('uuid', 'extra'), - } - - self.baremetal_mock.chassis.list.assert_called_with( - **kwargs - ) - - def test_chassis_list_fields_multiple(self): - arglist = [ - '--fields', 'uuid', 'description', - '--fields', 'extra', - ] - verifylist = [ - ('fields', [['uuid', 'description'], ['extra']]) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'detail': False, - 'fields': ('uuid', 'description', 'extra') - } - - self.baremetal_mock.chassis.list.assert_called_with( - **kwargs - ) - - def test_chassis_list_invalid_fields(self): - arglist = [ - '--fields', 'uuid', 'invalid' - ] - verifylist = [ - ('fields', [['uuid', 'invalid']]) - ] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_chassis_list_long_and_fields(self): - arglist = [ - '--long', - '--fields', 'uuid', 'invalid' - ] - verifylist = [ - ('long', True), - ('fields', [['uuid', 'invalid']]) - ] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestChassisSet(TestChassis): - def setUp(self): - super(TestChassisSet, self).setUp() - - self.baremetal_mock.chassis.update.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_CHASSIS), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_chassis.SetBaremetalChassis(self.app, None) - - def test_chassis_set_no_options(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_chassis_set_no_property(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [uuid] - verifylist = [('chassis', uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.assertFalse(self.baremetal_mock.chassis.update.called) - - def test_chassis_set_description(self): - description = 'new description' - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [ - uuid, - '--description', 'new description', - ] - verifylist = [ - ('chassis', uuid), - ('description', description) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.chassis.update.assert_called_once_with( - uuid, - [{'path': '/description', 'value': description, 'op': 'add'}] - ) - - def test_chassis_set_extra(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - extra = 'foo=bar' - arglist = [ - uuid, - '--extra', extra, - ] - verifylist = [ - ('chassis', uuid), - ('extra', [extra]) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.chassis.update.assert_called_once_with( - uuid, - [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}] - ) - - -class TestChassisShow(TestChassis): - def setUp(self): - super(TestChassisShow, self).setUp() - - self.baremetal_mock.chassis.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_CHASSIS), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_chassis.ShowBaremetalChassis(self.app, None) - - def test_chassis_show(self): - arglist = [baremetal_fakes.baremetal_chassis_uuid] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - # Set expected values - args = [baremetal_fakes.baremetal_chassis_uuid] - - self.baremetal_mock.chassis.get.assert_called_with( - *args, fields=None - ) - - collist = ( - 'description', - 'extra', - 'uuid' - ) - self.assertEqual(collist, columns) - self.assertNotIn('nodes', columns) - datalist = ( - baremetal_fakes.baremetal_chassis_description, - baremetal_fakes.baremetal_chassis_extra, - baremetal_fakes.baremetal_chassis_uuid, - ) - self.assertEqual(datalist, tuple(data)) - - def test_chassis_show_no_chassis(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_chassis_show_fields(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [ - uuid, - '--fields', 'uuid', 'description', - ] - verifylist = [ - ('chassis', uuid), - ('fields', [['uuid', 'description']]), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - args = [uuid] - fields = ['uuid', 'description'] - - self.baremetal_mock.chassis.get.assert_called_with( - *args, fields=fields - ) - - def test_chassis_show_fields_multiple(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [ - uuid, - '--fields', 'uuid', 'description', - '--fields', 'extra', - ] - verifylist = [ - ('chassis', uuid), - ('fields', [['uuid', 'description'], ['extra']]) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - args = [uuid] - fields = ['uuid', 'description', 'extra'] - - self.baremetal_mock.chassis.get.assert_called_with( - *args, fields=fields - ) - - def test_chassis_show_invalid_fields(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [ - uuid, - '--fields', 'uuid', 'invalid' - ] - verifylist = [ - ('chassis', uuid), - ('fields', [['uuid', 'invalid']]) - ] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestChassisUnset(TestChassis): - def setUp(self): - super(TestChassisUnset, self).setUp() - - self.baremetal_mock.chassis.update.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_CHASSIS), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_chassis.UnsetBaremetalChassis(self.app, None) - - def test_chassis_unset_no_options(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_chassis_unset_no_property(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [uuid] - verifylist = [('chassis', uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.assertFalse(self.baremetal_mock.chassis.update.called) - - def test_chassis_unset_description(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [ - uuid, - '--description', - ] - verifylist = [ - ('chassis', uuid), - ('description', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.chassis.update.assert_called_once_with( - uuid, - [{'path': '/description', 'op': 'remove'}] - ) - - def test_chassis_unset_extra(self): - uuid = baremetal_fakes.baremetal_chassis_uuid - arglist = [ - uuid, - '--extra', 'foo', - ] - verifylist = [ - ('chassis', uuid), - ('extra', ['foo']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.chassis.update.assert_called_once_with( - uuid, - [{'path': '/extra/foo', 'op': 'remove'}] - ) diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_create.py b/ironicclient/tests/unit/osc/v1/test_baremetal_create.py deleted file mode 100644 index f3cfbf1..0000000 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_create.py +++ /dev/null @@ -1,78 +0,0 @@ -# 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 copy -import mock - -from ironicclient import exc -from ironicclient.osc.v1 import baremetal_create -from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes -from ironicclient.v1 import create_resources - - -class TestBaremetalCreate(baremetal_fakes.TestBaremetal): - def setUp(self): - super(TestBaremetalCreate, self).setUp() - self.cmd = baremetal_create.CreateBaremetal(self.app, None) - - def test_baremetal_create_with_driver(self): - self.baremetal_mock = self.app.client_manager.baremetal - self.baremetal_mock.reset_mock() - self.baremetal_mock.node.create.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL), - loaded=True, - )) - - arglist = ['--driver', 'fake_driver'] - verifylist = [('driver', 'fake_driver')] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - self.assertEqual(('chassis_uuid', - 'instance_uuid', - 'maintenance', - 'name', - 'power_state', - 'provision_state', - 'uuid'), columns) - self.assertEqual( - (baremetal_fakes.baremetal_chassis_uuid_empty, - baremetal_fakes.baremetal_instance_uuid, - baremetal_fakes.baremetal_maintenance, - baremetal_fakes.baremetal_name, - baremetal_fakes.baremetal_power_state, - baremetal_fakes.baremetal_provision_state, - baremetal_fakes.baremetal_uuid), tuple(data)) - - self.baremetal_mock.node.create.assert_called_once_with( - driver='fake_driver') - - def test_baremetal_create_no_args(self): - parsed_args = self.check_parser(self.cmd, [], []) - self.assertRaises(exc.ValidationError, - self.cmd.take_action, parsed_args) - - @mock.patch.object(create_resources, 'create_resources', autospec=True) - def test_baremetal_create_resource_files(self, mock_create): - arglist = ['file.yaml', 'file.json'] - verifylist = [('resource_files', ['file.yaml', 'file.json'])] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.assertEqual((tuple(), tuple()), self.cmd.take_action(parsed_args)) - mock_create.assert_called_once_with(self.app.client_manager.baremetal, - ['file.yaml', 'file.json']) diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_driver.py b/ironicclient/tests/unit/osc/v1/test_baremetal_driver.py deleted file mode 100644 index 85bfa79..0000000 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_driver.py +++ /dev/null @@ -1,406 +0,0 @@ -# Copyright (c) 2016 Mirantis, Inc. -# -# 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 copy - -from osc_lib.tests import utils as oscutils - -from ironicclient.osc.v1 import baremetal_driver -from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes - - -class TestBaremetalDriver(baremetal_fakes.TestBaremetal): - - def setUp(self): - super(TestBaremetalDriver, self).setUp() - - self.baremetal_mock = self.app.client_manager.baremetal - self.baremetal_mock.reset_mock() - - -class TestListBaremetalDriver(TestBaremetalDriver): - - def setUp(self): - super(TestListBaremetalDriver, self).setUp() - - self.baremetal_mock.driver.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_DRIVER), - loaded=True) - ] - self.cmd = baremetal_driver.ListBaremetalDriver(self.app, None) - - def test_baremetal_driver_list(self): - arglist = [] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - collist = ( - "Supported driver(s)", - "Active host(s)") - self.assertEqual(collist, tuple(columns)) - - datalist = (( - baremetal_fakes.baremetal_driver_name, - ', '.join(baremetal_fakes.baremetal_driver_hosts)), ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_driver_list_with_type(self): - arglist = ['--type', baremetal_fakes.baremetal_driver_type] - verifylist = [('type', baremetal_fakes.baremetal_driver_type)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - collist = ( - "Supported driver(s)", - "Active host(s)") - self.assertEqual(collist, tuple(columns)) - - datalist = (( - baremetal_fakes.baremetal_driver_name, - ', '.join(baremetal_fakes.baremetal_driver_hosts)),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_driver_list_with_detail(self): - arglist = ['--long'] - verifylist = [('long', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - collist = ( - "Supported driver(s)", - "Type", - "Active host(s)", - 'Default Boot Interface', - 'Default Console Interface', - 'Default Deploy Interface', - 'Default Inspect Interface', - 'Default Management Interface', - 'Default Network Interface', - 'Default Power Interface', - 'Default RAID Interface', - 'Default Storage Interface', - 'Default Vendor Interface', - 'Enabled Boot Interfaces', - 'Enabled Console Interfaces', - 'Enabled Deploy Interfaces', - 'Enabled Inspect Interfaces', - 'Enabled Management Interfaces', - 'Enabled Network Interfaces', - 'Enabled Power Interfaces', - 'Enabled RAID Interfaces', - 'Enabled Storage Interfaces', - 'Enabled Vendor Interfaces' - ) - self.assertEqual(collist, tuple(columns)) - - datalist = (( - baremetal_fakes.baremetal_driver_name, - baremetal_fakes.baremetal_driver_type, - ', '.join(baremetal_fakes.baremetal_driver_hosts), - baremetal_fakes.baremetal_driver_default_boot_if, - baremetal_fakes.baremetal_driver_default_console_if, - baremetal_fakes.baremetal_driver_default_deploy_if, - baremetal_fakes.baremetal_driver_default_inspect_if, - baremetal_fakes.baremetal_driver_default_management_if, - baremetal_fakes.baremetal_driver_default_network_if, - baremetal_fakes.baremetal_driver_default_power_if, - baremetal_fakes.baremetal_driver_default_raid_if, - baremetal_fakes.baremetal_driver_default_storage_if, - baremetal_fakes.baremetal_driver_default_vendor_if, - ', '.join(baremetal_fakes.baremetal_driver_enabled_boot_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_console_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_deploy_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_inspect_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_management_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_network_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_power_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_raid_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_storage_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_vendor_ifs), - ),) - self.assertEqual(datalist, tuple(data)) - - -class TestListBaremetalDriverProperty(TestBaremetalDriver): - - def setUp(self): - super(TestListBaremetalDriverProperty, self).setUp() - - self.baremetal_mock.driver.properties.return_value = { - 'property1': 'description1', 'property2': 'description2'} - self.cmd = baremetal_driver.ListBaremetalDriverProperty( - self.app, None) - - def test_baremetal_driver_property_list(self): - arglist = ['fakedrivername'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - self.baremetal_mock.driver.properties.assert_called_with(*arglist) - - collist = ['Property', 'Description'] - self.assertEqual(collist, columns) - expected_data = [('property1', 'description1'), - ('property2', 'description2')] - self.assertEqual(expected_data, data) - - def test_baremetal_driver_list_no_arg(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestListBaremetalDriverRaidProperty(TestBaremetalDriver): - - def setUp(self): - super(TestListBaremetalDriverRaidProperty, self).setUp() - - (self.baremetal_mock.driver. - raid_logical_disk_properties.return_value) = { - 'RAIDProperty1': 'driver_raid_property1', - 'RAIDProperty2': 'driver_raid_property2', - } - - self.cmd = ( - baremetal_driver.ListBaremetalDriverRaidProperty( - self.app, None)) - - def test_baremetal_driver_raid_property_list(self): - arglist = ['fakedrivername'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - (self.baremetal_mock.driver. - raid_logical_disk_properties.assert_called_with(*arglist)) - - collist = ('Property', 'Description') - self.assertEqual(collist, tuple(columns)) - - expected_data = [('RAIDProperty1', 'driver_raid_property1'), - ('RAIDProperty2', 'driver_raid_property2')] - self.assertEqual(expected_data, data) - - def test_baremetal_driver_raid_property_list_no_arg(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestPassthruCallBaremetalDriver(TestBaremetalDriver): - - def setUp(self): - super(TestPassthruCallBaremetalDriver, self).setUp() - - self.baremetal_mock.driver.vendor_passthru.return_value = ( - baremetal_fakes.BAREMETAL_DRIVER_PASSTHRU - ) - - self.cmd = baremetal_driver.PassthruCallBaremetalDriver(self.app, None) - - def test_baremetal_driver_passthru_call_with_min_args(self): - - arglist = [ - baremetal_fakes.baremetal_driver_name, - baremetal_fakes.baremetal_driver_passthru_method, - ] - - verifylist = [ - ('driver', baremetal_fakes.baremetal_driver_name), - ('method', baremetal_fakes.baremetal_driver_passthru_method), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - # Set expected values - args = [ - baremetal_fakes.baremetal_driver_name, - baremetal_fakes.baremetal_driver_passthru_method, - ] - kwargs = { - 'http_method': 'POST', - 'args': {} - } - (self.baremetal_mock.driver.vendor_passthru. - assert_called_once_with(*args, **kwargs)) - - def test_baremetal_driver_passthru_call_with_all_args(self): - - arglist = [ - baremetal_fakes.baremetal_driver_name, - baremetal_fakes.baremetal_driver_passthru_method, - '--arg', 'arg1=val1', '--arg', 'arg2=val2', - '--http-method', 'POST' - ] - - verifylist = [ - ('driver', baremetal_fakes.baremetal_driver_name), - ('method', baremetal_fakes.baremetal_driver_passthru_method), - ('arg', ['arg1=val1', 'arg2=val2']), - ('http_method', 'POST') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - # Set expected values - args = [ - baremetal_fakes.baremetal_driver_name, - baremetal_fakes.baremetal_driver_passthru_method, - ] - kwargs = { - 'http_method': 'POST', - 'args': {'arg1': 'val1', 'arg2': 'val2'} - } - (self.baremetal_mock.driver.vendor_passthru. - assert_called_once_with(*args, **kwargs)) - - def test_baremetal_driver_passthru_call_no_arg(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestPassthruListBaremetalDriver(TestBaremetalDriver): - - def setUp(self): - super(TestPassthruListBaremetalDriver, self).setUp() - - self.baremetal_mock.driver.get_vendor_passthru_methods.return_value = ( - baremetal_fakes.BAREMETAL_DRIVER_PASSTHRU - ) - self.cmd = baremetal_driver.PassthruListBaremetalDriver(self.app, None) - - def test_baremetal_driver_passthru_list(self): - arglist = ['fakedrivername'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - args = ['fakedrivername'] - (self.baremetal_mock.driver.get_vendor_passthru_methods. - assert_called_with(*args)) - - collist = ( - "Name", - "Supported HTTP methods", - "Async", - "Description", - "Response is attachment", - ) - self.assertEqual(collist, tuple(columns)) - - datalist = (('lookup', 'POST', 'false', '', 'false'),) - - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_driver_passthru_list_no_arg(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestShowBaremetalDriver(TestBaremetalDriver): - - def setUp(self): - super(TestShowBaremetalDriver, self).setUp() - - self.baremetal_mock.driver.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_DRIVER), - loaded=True)) - self.cmd = baremetal_driver.ShowBaremetalDriver(self.app, None) - - def test_baremetal_driver_show(self): - arglist = ['fakedrivername'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - args = ['fakedrivername'] - self.baremetal_mock.driver.get.assert_called_with(*args) - self.assertFalse(self.baremetal_mock.driver.properties.called) - - collist = ('default_boot_interface', 'default_console_interface', - 'default_deploy_interface', 'default_inspect_interface', - 'default_management_interface', 'default_network_interface', - 'default_power_interface', 'default_raid_interface', - 'default_storage_interface', 'default_vendor_interface', - 'enabled_boot_interfaces', 'enabled_console_interfaces', - 'enabled_deploy_interfaces', 'enabled_inspect_interfaces', - 'enabled_management_interfaces', - 'enabled_network_interfaces', 'enabled_power_interfaces', - 'enabled_raid_interfaces', 'enabled_storage_interfaces', - 'enabled_vendor_interfaces', 'hosts', 'name', 'type') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_driver_default_boot_if, - baremetal_fakes.baremetal_driver_default_console_if, - baremetal_fakes.baremetal_driver_default_deploy_if, - baremetal_fakes.baremetal_driver_default_inspect_if, - baremetal_fakes.baremetal_driver_default_management_if, - baremetal_fakes.baremetal_driver_default_network_if, - baremetal_fakes.baremetal_driver_default_power_if, - baremetal_fakes.baremetal_driver_default_raid_if, - baremetal_fakes.baremetal_driver_default_storage_if, - baremetal_fakes.baremetal_driver_default_vendor_if, - ', '.join(baremetal_fakes.baremetal_driver_enabled_boot_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_console_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_deploy_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_inspect_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_management_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_network_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_power_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_raid_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_storage_ifs), - ', '.join(baremetal_fakes.baremetal_driver_enabled_vendor_ifs), - ', '.join(baremetal_fakes.baremetal_driver_hosts), - baremetal_fakes.baremetal_driver_name, - baremetal_fakes.baremetal_driver_type) - - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_driver_show_no_arg(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py deleted file mode 100644 index 3383214..0000000 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py +++ /dev/null @@ -1,2622 +0,0 @@ -# -# Copyright 2015 Red Hat, Inc. -# -# 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 copy -import mock - -from osc_lib.tests import utils as oscutils - -from ironicclient.common import utils as commonutils -from ironicclient import exc -from ironicclient.osc.v1 import baremetal_node -from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes -from ironicclient.v1 import utils as v1_utils - - -class TestBaremetal(baremetal_fakes.TestBaremetal): - - def setUp(self): - super(TestBaremetal, self).setUp() - - # Get a shortcut to the baremetal manager mock - self.baremetal_mock = self.app.client_manager.baremetal - self.baremetal_mock.reset_mock() - - -class TestAdopt(TestBaremetal): - def setUp(self): - super(TestAdopt, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.AdoptBaremetalNode(self.app, None) - - def test_adopt(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'adopt'), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'adopt', cleansteps=None, configdrive=None) - - def test_adopt_no_wait(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'adopt') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.wait_for_provision_state.assert_not_called() - - def test_adopt_baremetal_provision_state_active_and_wait(self): - arglist = ['node_uuid', - '--wait', '15'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'adopt'), - ('wait_timeout', 15) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='active', - poll_interval=2, timeout=15) - - def test_adopt_baremetal_provision_state_default_wait(self): - arglist = ['node_uuid', - '--wait'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'adopt'), - ('wait_timeout', 0) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='active', - poll_interval=2, timeout=0) - - -class TestBootdeviceSet(TestBaremetal): - def setUp(self): - super(TestBootdeviceSet, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.BootdeviceSetBaremetalNode(self.app, None) - - def test_bootdevice_set(self): - arglist = ['node_uuid', 'bios'] - verifylist = [('node', 'node_uuid'), - ('device', 'bios')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_boot_device.assert_called_once_with( - 'node_uuid', 'bios', False) - - def test_bootdevice_set_persistent(self): - arglist = ['node_uuid', 'bios', '--persistent'] - verifylist = [('node', 'node_uuid'), - ('device', 'bios'), - ('persistent', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_boot_device.assert_called_once_with( - 'node_uuid', 'bios', True) - - def test_bootdevice_set_invalid_device(self): - arglist = ['node_uuid', 'foo'] - verifylist = [('node', 'node_uuid'), - ('device', 'foo')] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_bootdevice_set_device_only(self): - arglist = ['bios'] - verifylist = [('device', 'bios')] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestBootdeviceShow(TestBaremetal): - def setUp(self): - super(TestBootdeviceShow, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.BootdeviceShowBaremetalNode(self.app, None) - - self.baremetal_mock.node.get_boot_device.return_value = { - "boot_device": "pxe", "persistent": False} - - self.baremetal_mock.node.get_supported_boot_devices.return_value = { - "supported_boot_devices": v1_utils.BOOT_DEVICES} - - def test_bootdevice_show(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.get_boot_device.assert_called_once_with( - 'node_uuid') - - def test_bootdevice_supported_show(self): - arglist = ['node_uuid', '--supported'] - verifylist = [('node', 'node_uuid'), ('supported', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - mock = self.baremetal_mock.node.get_supported_boot_devices - mock.assert_called_once_with('node_uuid') - - -class TestConsoleDisable(TestBaremetal): - def setUp(self): - super(TestConsoleDisable, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.ConsoleDisableBaremetalNode(self.app, None) - - def test_console_disable(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_console_mode.assert_called_once_with( - 'node_uuid', False) - - -class TestConsoleEnable(TestBaremetal): - def setUp(self): - super(TestConsoleEnable, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.ConsoleEnableBaremetalNode(self.app, None) - - def test_console_enable(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_console_mode.assert_called_once_with( - 'node_uuid', True) - - -class TestConsoleShow(TestBaremetal): - def setUp(self): - super(TestConsoleShow, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.ConsoleShowBaremetalNode(self.app, None) - - self.baremetal_mock.node.get_console.return_value = { - "console_enabled": False, "console_info": None} - - def test_console_show(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.get_console.assert_called_once_with( - 'node_uuid') - - -class TestBaremetalCreate(TestBaremetal): - def setUp(self): - super(TestBaremetalCreate, self).setUp() - - self.baremetal_mock.node.create.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_node.CreateBaremetalNode(self.app, None) - self.arglist = ['--driver', 'fake_driver'] - self.verifylist = [('driver', 'fake_driver')] - self.collist = ('chassis_uuid', - 'instance_uuid', - 'maintenance', - 'name', - 'power_state', - 'provision_state', - 'uuid' - ) - self.datalist = ( - baremetal_fakes.baremetal_chassis_uuid_empty, - baremetal_fakes.baremetal_instance_uuid, - baremetal_fakes.baremetal_maintenance, - baremetal_fakes.baremetal_name, - baremetal_fakes.baremetal_power_state, - baremetal_fakes.baremetal_provision_state, - baremetal_fakes.baremetal_uuid, - ) - self.actual_kwargs = { - 'driver': 'fake_driver', - } - - def check_with_options(self, addl_arglist, addl_verifylist, addl_kwargs): - arglist = copy.copy(self.arglist) + addl_arglist - verifylist = copy.copy(self.verifylist) + addl_verifylist - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - collist = copy.copy(self.collist) - self.assertEqual(collist, columns) - - datalist = copy.copy(self.datalist) - self.assertEqual(datalist, tuple(data)) - - kwargs = copy.copy(self.actual_kwargs) - kwargs.update(addl_kwargs) - - self.baremetal_mock.node.create.assert_called_once_with(**kwargs) - - def test_baremetal_create_no_options(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_create_with_driver(self): - arglist = copy.copy(self.arglist) - - verifylist = copy.copy(self.verifylist) - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - collist = copy.copy(self.collist) - self.assertEqual(collist, columns) - self.assertNotIn('ports', columns) - self.assertNotIn('states', columns) - - datalist = copy.copy(self.datalist) - self.assertEqual(datalist, tuple(data)) - - kwargs = copy.copy(self.actual_kwargs) - - self.baremetal_mock.node.create.assert_called_once_with(**kwargs) - - def test_baremetal_create_with_chassis(self): - self.check_with_options(['--chassis-uuid', 'chassis_uuid'], - [('chassis_uuid', 'chassis_uuid')], - {'chassis_uuid': 'chassis_uuid'}) - - def test_baremetal_create_with_driver_info(self): - self.check_with_options(['--driver-info', 'arg1=val1', - '--driver-info', 'arg2=val2'], - [('driver_info', - ['arg1=val1', - 'arg2=val2'])], - {'driver_info': { - 'arg1': 'val1', - 'arg2': 'val2'}}) - - def test_baremetal_create_with_properties(self): - self.check_with_options(['--property', 'arg1=val1', - '--property', 'arg2=val2'], - [('properties', - ['arg1=val1', - 'arg2=val2'])], - {'properties': { - 'arg1': 'val1', - 'arg2': 'val2'}}) - - def test_baremetal_create_with_extra(self): - self.check_with_options(['--extra', 'arg1=val1', - '--extra', 'arg2=val2'], - [('extra', - ['arg1=val1', - 'arg2=val2'])], - {'extra': { - 'arg1': 'val1', - 'arg2': 'val2'}}) - - def test_baremetal_create_with_uuid(self): - self.check_with_options(['--uuid', 'uuid'], - [('uuid', 'uuid')], - {'uuid': 'uuid'}) - - def test_baremetal_create_with_name(self): - self.check_with_options(['--name', 'name'], - [('name', 'name')], - {'name': 'name'}) - - def test_baremetal_create_with_boot_interface(self): - self.check_with_options(['--boot-interface', 'boot'], - [('boot_interface', 'boot')], - {'boot_interface': 'boot'}) - - def test_baremetal_create_with_console_interface(self): - self.check_with_options(['--console-interface', 'console'], - [('console_interface', 'console')], - {'console_interface': 'console'}) - - def test_baremetal_create_with_deploy_interface(self): - self.check_with_options(['--deploy-interface', 'deploy'], - [('deploy_interface', 'deploy')], - {'deploy_interface': 'deploy'}) - - def test_baremetal_create_with_inspect_interface(self): - self.check_with_options(['--inspect-interface', 'inspect'], - [('inspect_interface', 'inspect')], - {'inspect_interface': 'inspect'}) - - def test_baremetal_create_with_management_interface(self): - self.check_with_options(['--management-interface', 'management'], - [('management_interface', 'management')], - {'management_interface': 'management'}) - - def test_baremetal_create_with_network_interface(self): - self.check_with_options(['--network-interface', 'neutron'], - [('network_interface', 'neutron')], - {'network_interface': 'neutron'}) - - def test_baremetal_create_with_power_interface(self): - self.check_with_options(['--power-interface', 'power'], - [('power_interface', 'power')], - {'power_interface': 'power'}) - - def test_baremetal_create_with_raid_interface(self): - self.check_with_options(['--raid-interface', 'raid'], - [('raid_interface', 'raid')], - {'raid_interface': 'raid'}) - - def test_baremetal_create_with_storage_interface(self): - self.check_with_options(['--storage-interface', 'storage'], - [('storage_interface', 'storage')], - {'storage_interface': 'storage'}) - - def test_baremetal_create_with_vendor_interface(self): - self.check_with_options(['--vendor-interface', 'vendor'], - [('vendor_interface', 'vendor')], - {'vendor_interface': 'vendor'}) - - def test_baremetal_create_with_resource_class(self): - self.check_with_options(['--resource-class', 'foo'], - [('resource_class', 'foo')], - {'resource_class': 'foo'}) - - -class TestBaremetalDelete(TestBaremetal): - def setUp(self): - super(TestBaremetalDelete, self).setUp() - - self.baremetal_mock.node.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_node.DeleteBaremetalNode(self.app, None) - - def test_baremetal_delete(self): - arglist = ['xxx-xxxxxx-xxxx'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - args = 'xxx-xxxxxx-xxxx' - - self.baremetal_mock.node.delete.assert_called_with( - args - ) - - def test_baremetal_delete_multiple(self): - arglist = ['xxx-xxxxxx-xxxx', 'fakename'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - args = ['xxx-xxxxxx-xxxx', 'fakename'] - self.baremetal_mock.node.delete.has_calls( - [mock.call(x) for x in args] - ) - self.assertEqual(2, self.baremetal_mock.node.delete.call_count) - - def test_baremetal_delete_multiple_with_failure(self): - arglist = ['xxx-xxxxxx-xxxx', 'badname'] - verifylist = [] - - self.baremetal_mock.node.delete.side_effect = ['', exc.ClientException] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.assertRaises(exc.ClientException, - self.cmd.take_action, - parsed_args) - - # Set expected values - args = ['xxx-xxxxxx-xxxx', 'badname'] - self.baremetal_mock.node.delete.has_calls( - [mock.call(x) for x in args] - ) - self.assertEqual(2, self.baremetal_mock.node.delete.call_count) - - -class TestBaremetalList(TestBaremetal): - - def setUp(self): - super(TestBaremetalList, self).setUp() - - self.baremetal_mock.node.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL), - loaded=True, - ), - ] - - # Get the command object to test - self.cmd = baremetal_node.ListBaremetalNode(self.app, None) - - def test_baremetal_list_no_options(self): - arglist = [] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - collist = ( - "UUID", - "Name", - "Instance UUID", - "Power State", - "Provisioning State", - "Maintenance" - ) - self.assertEqual(collist, columns) - datalist = (( - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_name, - baremetal_fakes.baremetal_instance_uuid, - baremetal_fakes.baremetal_power_state, - baremetal_fakes.baremetal_provision_state, - baremetal_fakes.baremetal_maintenance, - ), ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_list_long(self): - arglist = [ - '--long', - ] - verifylist = [ - ('long', True), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'detail': True, - 'marker': None, - 'limit': None, - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - collist = ('Chassis UUID', 'Created At', 'Clean Step', - 'Console Enabled', 'Driver', 'Driver Info', - 'Driver Internal Info', 'Extra', 'Instance Info', - 'Instance UUID', 'Last Error', 'Maintenance', - 'Maintenance Reason', 'Power State', 'Properties', - 'Provisioning State', 'Provision Updated At', - 'Current RAID configuration', 'Reservation', - 'Resource Class', - 'Target Power State', 'Target Provision State', - 'Target RAID configuration', - 'Updated At', 'Inspection Finished At', - 'Inspection Started At', 'UUID', 'Name', - 'Boot Interface', 'Console Interface', - 'Deploy Interface', 'Inspect Interface', - 'Management Interface', 'Network Interface', - 'Power Interface', 'RAID Interface', - 'Storage Interface', 'Vendor Interface') - self.assertEqual(collist, columns) - datalist = (( - '', - '', - '', - '', - '', - '', - '', - '', - '', - baremetal_fakes.baremetal_instance_uuid, - '', - baremetal_fakes.baremetal_maintenance, - '', - baremetal_fakes.baremetal_power_state, - '', - baremetal_fakes.baremetal_provision_state, - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_name, - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - ), ) - self.assertEqual(datalist, tuple(data)) - - def _test_baremetal_list_maintenance(self, maint_option, maint_value): - arglist = [ - maint_option, - ] - verifylist = [ - ('maintenance', maint_value), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'maintenance': maint_value, - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_maintenance(self): - self._test_baremetal_list_maintenance('--maintenance', True) - - def test_baremetal_list_no_maintenance(self): - self._test_baremetal_list_maintenance('--no-maintenance', False) - - def test_baremetal_list_none_maintenance(self): - arglist = [ - ] - verifylist = [ - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_both_maintenances(self): - arglist = [ - '--maintenance', - '--no-maintenance', - ] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_list_associated(self): - arglist = [ - '--associated', - ] - verifylist = [ - ('associated', True), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'associated': True, - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_unassociated(self): - arglist = [ - '--unassociated', - ] - verifylist = [ - ('associated', False), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'associated': False, - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_both_associated_unassociated_not_allowed(self): - arglist = [ - '--associated', '--unassociated', - ] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_list_provision_state(self): - arglist = [ - '--provision-state', 'active', - ] - verifylist = [ - ('provision_state', 'active'), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'provision_state': 'active' - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_driver(self): - arglist = [ - '--driver', 'ipmi', - ] - verifylist = [ - ('driver', 'ipmi'), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'driver': 'ipmi' - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_resource_class(self): - arglist = [ - '--resource-class', 'foo', - ] - verifylist = [ - ('resource_class', 'foo'), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'resource_class': 'foo' - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_chassis(self): - chassis_uuid = 'aaaaaaaa-1111-bbbb-2222-cccccccccccc' - arglist = [ - '--chassis', chassis_uuid, - ] - verifylist = [ - ('chassis', chassis_uuid), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'chassis': chassis_uuid - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_fields(self): - arglist = [ - '--fields', 'uuid', 'name', - ] - verifylist = [ - ('fields', [['uuid', 'name']]), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'detail': False, - 'fields': ('uuid', 'name'), - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_fields_multiple(self): - arglist = [ - '--fields', 'uuid', 'name', - '--fields', 'extra', - ] - verifylist = [ - ('fields', [['uuid', 'name'], ['extra']]) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - kwargs = { - 'marker': None, - 'limit': None, - 'detail': False, - 'fields': ('uuid', 'name', 'extra') - } - - self.baremetal_mock.node.list.assert_called_with( - **kwargs - ) - - def test_baremetal_list_invalid_fields(self): - arglist = [ - '--fields', 'uuid', 'invalid' - ] - verifylist = [ - ('fields', [['uuid', 'invalid']]) - ] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestBaremetalMaintenanceSet(TestBaremetal): - def setUp(self): - super(TestBaremetalMaintenanceSet, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.MaintenanceSetBaremetalNode(self.app, None) - - def test_baremetal_maintenance_on(self): - arglist = ['node_uuid', - '--reason', 'maintenance reason'] - verifylist = [ - ('node', 'node_uuid'), - ('reason', 'maintenance reason'), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_maintenance.assert_called_once_with( - 'node_uuid', - True, - maint_reason='maintenance reason' - ) - - def test_baremetal_maintenance_on_no_reason(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_maintenance.assert_called_once_with( - 'node_uuid', - True, - maint_reason=None - ) - - -class TestBaremetalMaintenanceUnset(TestBaremetal): - def setUp(self): - super(TestBaremetalMaintenanceUnset, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.MaintenanceUnsetBaremetalNode(self.app, None) - - def test_baremetal_maintenance_off(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_maintenance.assert_called_once_with( - 'node_uuid', - False) - - -class TestPassthruCall(TestBaremetal): - def setUp(self): - super(TestPassthruCall, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.PassthruCallBaremetalNode(self.app, None) - - def test_passthru_call(self): - arglist = ['node_uuid', 'heartbeat'] - verifylist = [('node', 'node_uuid'), - ('method', 'heartbeat')] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.node.vendor_passthru.assert_called_once_with( - 'node_uuid', 'heartbeat', http_method='POST', args={}) - - def test_passthru_call_http_method(self): - arglist = ['node_uuid', 'heartbeat', '--http-method', 'PUT'] - verifylist = [('node', 'node_uuid'), - ('method', 'heartbeat'), - ('http_method', 'PUT')] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.node.vendor_passthru.assert_called_once_with( - 'node_uuid', 'heartbeat', http_method='PUT', args={}) - - def test_passthru_call_args(self): - arglist = ['node_uuid', 'heartbeat', - '--arg', 'key1=value1', '--arg', 'key2=value2'] - verifylist = [('node', 'node_uuid'), - ('method', 'heartbeat'), - ('arg', ['key1=value1', 'key2=value2'])] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - expected_dict = {'key1': 'value1', 'key2': 'value2'} - self.baremetal_mock.node.vendor_passthru.assert_called_once_with( - 'node_uuid', 'heartbeat', http_method='POST', args=expected_dict) - - -class TestPassthruList(TestBaremetal): - def setUp(self): - super(TestPassthruList, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.PassthruListBaremetalNode(self.app, None) - - self.baremetal_mock.node.get_vendor_passthru_methods.return_value = { - "send_raw": {"require_exclusive_lock": True, "attach": False, - "http_methods": ["POST"], "description": "", - "async": True}, - "bmc_reset": {"require_exclusive_lock": True, "attach": False, - "http_methods": ["POST"], "description": "", - "async": True}} - - def test_passthru_list(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - mock = self.baremetal_mock.node.get_vendor_passthru_methods - mock.assert_called_once_with('node_uuid') - - -class TestBaremetalPower(TestBaremetal): - def setUp(self): - super(TestBaremetalPower, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.PowerBaremetalNode(self.app, None) - - def test_baremetal_power_just_on(self): - arglist = ['on'] - verifylist = [('power_state', 'on')] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_power_just_off(self): - arglist = ['off'] - verifylist = [('power_state', 'off')] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_power_uuid_only(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_power_on(self): - arglist = ['on', 'node_uuid'] - verifylist = [('power_state', 'on'), - ('node', 'node_uuid'), - ('soft', False), - ('power_timeout', None)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'on', False, timeout=None) - - def test_baremetal_power_on_timeout(self): - arglist = ['on', 'node_uuid', '--power-timeout', '2'] - verifylist = [('power_state', 'on'), - ('node', 'node_uuid'), - ('soft', False), - ('power_timeout', 2)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'on', False, timeout=2) - - def test_baremetal_power_off(self): - arglist = ['off', 'node_uuid'] - verifylist = [('power_state', 'off'), - ('node', 'node_uuid'), - ('soft', False), - ('power_timeout', None)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'off', False, timeout=None) - - def test_baremetal_power_off_timeout(self): - arglist = ['off', 'node_uuid', '--power-timeout', '2'] - verifylist = [('power_state', 'off'), - ('node', 'node_uuid'), - ('soft', False), - ('power_timeout', 2)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'off', False, timeout=2) - - def test_baremetal_soft_power_off(self): - arglist = ['off', 'node_uuid', '--soft'] - verifylist = [('power_state', 'off'), - ('node', 'node_uuid'), - ('soft', True), - ('power_timeout', None)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'off', True, timeout=None) - - def test_baremetal_soft_power_off_timeout(self): - arglist = ['off', 'node_uuid', '--soft', '--power-timeout', '2'] - verifylist = [('power_state', 'off'), - ('node', 'node_uuid'), - ('soft', True), - ('power_timeout', 2)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'off', True, timeout=2) - - -class TestDeployBaremetalProvisionState(TestBaremetal): - def setUp(self): - super(TestDeployBaremetalProvisionState, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.DeployBaremetalNode(self.app, None) - - def test_deploy_baremetal_provision_state_active_and_configdrive(self): - arglist = ['node_uuid', - '--config-drive', 'path/to/drive'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'active'), - ('config_drive', 'path/to/drive'), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'active', - cleansteps=None, configdrive='path/to/drive') - - def test_deploy_no_wait(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'active') - ] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.baremetal_mock.node.wait_for_provision_state.assert_not_called() - - def test_deploy_baremetal_provision_state_active_and_wait(self): - arglist = ['node_uuid', - '--wait', '15'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'active'), - ('wait_timeout', 15) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='active', - poll_interval=10, timeout=15) - - def test_deploy_baremetal_provision_state_default_wait(self): - arglist = ['node_uuid', - '--wait'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'active'), - ('wait_timeout', 0) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='active', - poll_interval=10, timeout=0) - - def test_deploy_baremetal_provision_state_mismatch(self): - arglist = ['node_uuid', - '--provision-state', 'abort'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'active'), - ] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestManageBaremetalProvisionState(TestBaremetal): - def setUp(self): - super(TestManageBaremetalProvisionState, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.ManageBaremetalNode(self.app, None) - - def test_manage_no_wait(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'manage') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.wait_for_provision_state.assert_not_called() - - def test_manage_baremetal_provision_state_manageable_and_wait(self): - arglist = ['node_uuid', - '--wait', '15'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'manage'), - ('wait_timeout', 15) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='manageable', - poll_interval=2, timeout=15) - - def test_manage_baremetal_provision_state_default_wait(self): - arglist = ['node_uuid', - '--wait'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'manage'), - ('wait_timeout', 0) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='manageable', - poll_interval=2, timeout=0) - - -class TestCleanBaremetalProvisionState(TestBaremetal): - def setUp(self): - super(TestCleanBaremetalProvisionState, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.CleanBaremetalNode(self.app, None) - - def test_clean_no_wait(self): - arglist = ['node_uuid', '--clean-steps', '-'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'clean'), - ('clean_steps', '-') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.wait_for_provision_state.assert_not_called() - - def test_clean_baremetal_provision_state_manageable_and_wait(self): - arglist = ['node_uuid', - '--wait', '15', - '--clean-steps', '-'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'clean'), - ('wait_timeout', 15), - ('clean_steps', '-') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='manageable', - poll_interval=10, timeout=15) - - def test_clean_baremetal_provision_state_default_wait(self): - arglist = ['node_uuid', - '--wait', - '--clean-steps', '-'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'clean'), - ('wait_timeout', 0), - ('clean_steps', '-') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='manageable', - poll_interval=10, timeout=0) - - -class TestInspectBaremetalProvisionState(TestBaremetal): - def setUp(self): - super(TestInspectBaremetalProvisionState, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.InspectBaremetalNode(self.app, None) - - def test_inspect_no_wait(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'inspect') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.wait_for_provision_state.assert_not_called() - - def test_inspect_baremetal_provision_state_managable_and_wait(self): - arglist = ['node_uuid', - '--wait', '15'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'inspect'), - ('wait_timeout', 15) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='manageable', - poll_interval=2, timeout=15) - - def test_inspect_baremetal_provision_state_default_wait(self): - arglist = ['node_uuid', - '--wait'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'inspect'), - ('wait_timeout', 0) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='manageable', - poll_interval=2, timeout=0) - - -class TestProvideBaremetalProvisionState(TestBaremetal): - def setUp(self): - super(TestProvideBaremetalProvisionState, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.ProvideBaremetalNode(self.app, None) - - def test_provide_no_wait(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'provide') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.wait_for_provision_state.assert_not_called() - - def test_provide_baremetal_provision_state_available_and_wait(self): - arglist = ['node_uuid', - '--wait', '15'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'provide'), - ('wait_timeout', 15) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='available', - poll_interval=10, timeout=15) - - def test_provide_baremetal_provision_state_default_wait(self): - arglist = ['node_uuid', - '--wait'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'provide'), - ('wait_timeout', 0) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='available', - poll_interval=10, timeout=0) - - -class TestRebuildBaremetalProvisionState(TestBaremetal): - def setUp(self): - super(TestRebuildBaremetalProvisionState, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.RebuildBaremetalNode(self.app, None) - - def test_rebuild_no_wait(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'rebuild') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.wait_for_provision_state.assert_not_called() - - def test_rebuild_baremetal_provision_state_active_and_wait(self): - arglist = ['node_uuid', - '--wait', '15'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'rebuild'), - ('wait_timeout', 15) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='active', - poll_interval=10, timeout=15) - - def test_rebuild_baremetal_provision_state_default_wait(self): - arglist = ['node_uuid', - '--wait'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'rebuild'), - ('wait_timeout', 0) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='active', - poll_interval=10, timeout=0) - - -class TestUndeployBaremetalProvisionState(TestBaremetal): - def setUp(self): - super(TestUndeployBaremetalProvisionState, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.UndeployBaremetalNode(self.app, None) - - def test_undeploy_no_wait(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'deleted') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.wait_for_provision_state.assert_not_called() - - def test_undeploy_baremetal_provision_state_available_and_wait(self): - arglist = ['node_uuid', - '--wait', '15'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'deleted'), - ('wait_timeout', 15) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='available', - poll_interval=10, timeout=15) - - def test_undeploy_baremetal_provision_state_default_wait(self): - arglist = ['node_uuid', - '--wait'] - verifylist = [ - ('node', 'node_uuid'), - ('provision_state', 'deleted'), - ('wait_timeout', 0) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - test_node = self.baremetal_mock.node - test_node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='available', - poll_interval=10, timeout=0) - - -class TestBaremetalReboot(TestBaremetal): - def setUp(self): - super(TestBaremetalReboot, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.RebootBaremetalNode(self.app, None) - - def test_baremetal_reboot_no_options(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_reboot_uuid_only(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid'), - ('soft', False), - ('power_timeout', None)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'reboot', False, timeout=None) - - def test_baremetal_reboot_timeout(self): - arglist = ['node_uuid', '--power-timeout', '2'] - verifylist = [('node', 'node_uuid'), - ('soft', False), - ('power_timeout', 2)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'reboot', False, timeout=2) - - def test_baremetal_soft_reboot(self): - arglist = ['node_uuid', '--soft'] - verifylist = [('node', 'node_uuid'), - ('soft', True), - ('power_timeout', None)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'reboot', True, timeout=None) - - def test_baremetal_soft_reboot_timeout(self): - arglist = ['node_uuid', '--soft', '--power-timeout', '2'] - verifylist = [('node', 'node_uuid'), - ('soft', True), - ('power_timeout', 2)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', 'reboot', True, timeout=2) - - -class TestBaremetalSet(TestBaremetal): - def setUp(self): - super(TestBaremetalSet, self).setUp() - - self.baremetal_mock.node.update.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_node.SetBaremetalNode(self.app, None) - - def test_baremetal_set_no_options(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_set_no_property(self): - arglist = ['node_uuid'] - verifylist = [ - ('node', 'node_uuid'), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.assertFalse(self.baremetal_mock.node.update.called) - - def test_baremetal_set_one_property(self): - arglist = ['node_uuid', '--property', 'path/to/property=value'] - verifylist = [ - ('node', 'node_uuid'), - ('property', ['path/to/property=value']), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/properties/path/to/property', - 'value': 'value', - 'op': 'add'}]) - - def test_baremetal_set_multiple_properties(self): - arglist = [ - 'node_uuid', - '--property', 'path/to/property=value', - '--property', 'other/path=value2' - ] - verifylist = [ - ('node', 'node_uuid'), - ('property', - [ - 'path/to/property=value', - 'other/path=value2', - ]), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/properties/path/to/property', - 'value': 'value', - 'op': 'add'}, - {'path': '/properties/other/path', - 'value': 'value2', - 'op': 'add'}] - ) - - def test_baremetal_set_instance_uuid(self): - arglist = [ - 'node_uuid', - '--instance-uuid', 'xxxxx', - ] - verifylist = [ - ('node', 'node_uuid'), - ('instance_uuid', 'xxxxx') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/instance_uuid', 'value': 'xxxxx', 'op': 'add'}] - ) - - def test_baremetal_set_name(self): - arglist = [ - 'node_uuid', - '--name', 'xxxxx', - ] - verifylist = [ - ('node', 'node_uuid'), - ('name', 'xxxxx') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/name', 'value': 'xxxxx', 'op': 'add'}] - ) - - def test_baremetal_set_chassis(self): - chassis = '4f4135ea-7e58-4e3d-bcc4-b87ca16e980b' - arglist = [ - 'node_uuid', - '--chassis-uuid', chassis, - ] - verifylist = [ - ('node', 'node_uuid'), - ('chassis_uuid', chassis) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/chassis_uuid', 'value': chassis, 'op': 'add'}] - ) - - def test_baremetal_set_driver(self): - arglist = [ - 'node_uuid', - '--driver', 'xxxxx', - ] - verifylist = [ - ('node', 'node_uuid'), - ('driver', 'xxxxx') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/driver', 'value': 'xxxxx', 'op': 'add'}] - ) - - def _test_baremetal_set_hardware_interface(self, interface): - arglist = [ - 'node_uuid', - '--%s-interface' % interface, 'xxxxx', - ] - verifylist = [ - ('node', 'node_uuid'), - ('%s_interface' % interface, 'xxxxx') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/%s_interface' % interface, - 'value': 'xxxxx', 'op': 'add'}] - ) - - def test_baremetal_set_boot_interface(self): - self._test_baremetal_set_hardware_interface('boot') - - def test_baremetal_set_console_interface(self): - self._test_baremetal_set_hardware_interface('console') - - def test_baremetal_set_deploy_interface(self): - self._test_baremetal_set_hardware_interface('deploy') - - def test_baremetal_set_inspect_interface(self): - self._test_baremetal_set_hardware_interface('inspect') - - def test_baremetal_set_management_interface(self): - self._test_baremetal_set_hardware_interface('management') - - def test_baremetal_set_network_interface(self): - self._test_baremetal_set_hardware_interface('network') - - def test_baremetal_set_power_interface(self): - self._test_baremetal_set_hardware_interface('power') - - def test_baremetal_set_raid_interface(self): - self._test_baremetal_set_hardware_interface('raid') - - def test_baremetal_set_storage_interface(self): - self._test_baremetal_set_hardware_interface('storage') - - def test_baremetal_set_vendor_interface(self): - self._test_baremetal_set_hardware_interface('vendor') - - def test_baremetal_set_resource_class(self): - arglist = [ - 'node_uuid', - '--resource-class', 'foo', - ] - verifylist = [ - ('node', 'node_uuid'), - ('resource_class', 'foo') - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/resource_class', 'value': 'foo', 'op': 'add'}] - ) - - def test_baremetal_set_extra(self): - arglist = [ - 'node_uuid', - '--extra', 'foo=bar', - ] - verifylist = [ - ('node', 'node_uuid'), - ('extra', ['foo=bar']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}] - ) - - def test_baremetal_set_driver_info(self): - arglist = [ - 'node_uuid', - '--driver-info', 'foo=bar', - ] - verifylist = [ - ('node', 'node_uuid'), - ('driver_info', ['foo=bar']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/driver_info/foo', 'value': 'bar', 'op': 'add'}] - ) - - def test_baremetal_set_instance_info(self): - arglist = [ - 'node_uuid', - '--instance-info', 'foo=bar', - ] - verifylist = [ - ('node', 'node_uuid'), - ('instance_info', ['foo=bar']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/instance_info/foo', 'value': 'bar', 'op': 'add'}] - ) - - @mock.patch.object(commonutils, 'get_from_stdin', autospec=True) - @mock.patch.object(commonutils, 'handle_json_or_file_arg', autospec=True) - def test_baremetal_set_target_raid_config(self, mock_handle, mock_stdin): - target_raid_config_string = '{"raid": "config"}' - expected_target_raid_config = {'raid': 'config'} - mock_handle.return_value = expected_target_raid_config.copy() - - arglist = ['node_uuid', - '--target-raid-config', target_raid_config_string] - verifylist = [('node', 'node_uuid'), - ('target_raid_config', target_raid_config_string)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.assertFalse(mock_stdin.called) - mock_handle.assert_called_once_with(target_raid_config_string) - self.baremetal_mock.node.set_target_raid_config.\ - assert_called_once_with('node_uuid', expected_target_raid_config) - self.assertFalse(self.baremetal_mock.node.update.called) - - @mock.patch.object(commonutils, 'get_from_stdin', autospec=True) - @mock.patch.object(commonutils, 'handle_json_or_file_arg', autospec=True) - def test_baremetal_set_target_raid_config_and_name( - self, mock_handle, mock_stdin): - target_raid_config_string = '{"raid": "config"}' - expected_target_raid_config = {'raid': 'config'} - mock_handle.return_value = expected_target_raid_config.copy() - - arglist = ['node_uuid', - '--name', 'xxxxx', - '--target-raid-config', target_raid_config_string] - verifylist = [('node', 'node_uuid'), - ('name', 'xxxxx'), - ('target_raid_config', target_raid_config_string)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.assertFalse(mock_stdin.called) - mock_handle.assert_called_once_with(target_raid_config_string) - self.baremetal_mock.node.set_target_raid_config.\ - assert_called_once_with('node_uuid', expected_target_raid_config) - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/name', 'value': 'xxxxx', 'op': 'add'}]) - - @mock.patch.object(commonutils, 'get_from_stdin', autospec=True) - @mock.patch.object(commonutils, 'handle_json_or_file_arg', autospec=True) - def test_baremetal_set_target_raid_config_stdin(self, mock_handle, - mock_stdin): - target_value = '-' - target_raid_config_string = '{"raid": "config"}' - expected_target_raid_config = {'raid': 'config'} - mock_stdin.return_value = target_raid_config_string - mock_handle.return_value = expected_target_raid_config.copy() - - arglist = ['node_uuid', - '--target-raid-config', target_value] - verifylist = [('node', 'node_uuid'), - ('target_raid_config', target_value)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - mock_stdin.assert_called_once_with('target_raid_config') - mock_handle.assert_called_once_with(target_raid_config_string) - self.baremetal_mock.node.set_target_raid_config.\ - assert_called_once_with('node_uuid', expected_target_raid_config) - self.assertFalse(self.baremetal_mock.node.update.called) - - @mock.patch.object(commonutils, 'get_from_stdin', autospec=True) - @mock.patch.object(commonutils, 'handle_json_or_file_arg', autospec=True) - def test_baremetal_set_target_raid_config_stdin_exception( - self, mock_handle, mock_stdin): - target_value = '-' - mock_stdin.side_effect = exc.InvalidAttribute('bad') - - arglist = ['node_uuid', - '--target-raid-config', target_value] - verifylist = [('node', 'node_uuid'), - ('target_raid_config', target_value)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises(exc.InvalidAttribute, - self.cmd.take_action, parsed_args) - - mock_stdin.assert_called_once_with('target_raid_config') - self.assertFalse(mock_handle.called) - self.assertFalse( - self.baremetal_mock.node.set_target_raid_config.called) - self.assertFalse(self.baremetal_mock.node.update.called) - - -class TestBaremetalShow(TestBaremetal): - def setUp(self): - super(TestBaremetalShow, self).setUp() - - self.baremetal_mock.node.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL), - loaded=True, - )) - - self.baremetal_mock.node.get_by_instance_uuid.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_node.ShowBaremetalNode(self.app, None) - - def test_baremetal_show(self): - arglist = ['xxx-xxxxxx-xxxx'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - - # Set expected values - args = ['xxx-xxxxxx-xxxx'] - - self.baremetal_mock.node.get.assert_called_with( - *args, fields=None - ) - - collist = ('chassis_uuid', - 'instance_uuid', - 'maintenance', - 'name', - 'power_state', - 'provision_state', - 'uuid' - ) - self.assertEqual(collist, columns) - self.assertNotIn('ports', columns) - self.assertNotIn('states', columns) - datalist = ( - baremetal_fakes.baremetal_chassis_uuid_empty, - baremetal_fakes.baremetal_instance_uuid, - baremetal_fakes.baremetal_maintenance, - baremetal_fakes.baremetal_name, - baremetal_fakes.baremetal_power_state, - baremetal_fakes.baremetal_provision_state, - baremetal_fakes.baremetal_uuid - ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_show_no_node(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_show_with_instance_uuid(self): - arglist = [ - 'xxx-xxxxxx-xxxx', - '--instance', - ] - - verifylist = [ - ('instance_uuid', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = ['xxx-xxxxxx-xxxx'] - - self.baremetal_mock.node.get_by_instance_uuid.assert_called_with( - *args, fields=None - ) - - def test_baremetal_show_fields(self): - arglist = [ - 'xxxxx', - '--fields', 'uuid', 'name', - ] - verifylist = [ - ('node', 'xxxxx'), - ('fields', [['uuid', 'name']]), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - columns, data = self.cmd.take_action(parsed_args) - self.assertNotIn('chassis_uuid', columns) - - # Set expected values - args = ['xxxxx'] - fields = ['uuid', 'name'] - - self.baremetal_mock.node.get.assert_called_with( - *args, fields=fields - ) - - def test_baremetal_show_fields_multiple(self): - arglist = [ - 'xxxxx', - '--fields', 'uuid', 'name', - '--fields', 'extra', - ] - verifylist = [ - ('node', 'xxxxx'), - ('fields', [['uuid', 'name'], ['extra']]) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - columns, data = self.cmd.take_action(parsed_args) - self.assertNotIn('chassis_uuid', columns) - # Set expected values - args = ['xxxxx'] - fields = ['uuid', 'name', 'extra'] - - self.baremetal_mock.node.get.assert_called_with( - *args, fields=fields - ) - - def test_baremetal_show_invalid_fields(self): - arglist = [ - 'xxxxx', - '--fields', 'uuid', 'invalid' - ] - verifylist = [ - ('node', 'xxxxx'), - ('fields', [['uuid', 'invalid']]) - ] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestBaremetalUnset(TestBaremetal): - def setUp(self): - super(TestBaremetalUnset, self).setUp() - - self.baremetal_mock.node.update.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_node.UnsetBaremetalNode(self.app, None) - - def test_baremetal_unset_no_options(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_unset_no_property(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.assertFalse(self.baremetal_mock.node.update.called) - - def test_baremetal_unset_one_property(self): - arglist = ['node_uuid', '--property', 'path/to/property'] - verifylist = [('node', 'node_uuid'), - ('property', ['path/to/property'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/properties/path/to/property', 'op': 'remove'}]) - - def test_baremetal_unset_multiple_properties(self): - arglist = ['node_uuid', - '--property', 'path/to/property', - '--property', 'other/path'] - verifylist = [('node', 'node_uuid'), - ('property', - ['path/to/property', - 'other/path'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/properties/path/to/property', 'op': 'remove'}, - {'path': '/properties/other/path', 'op': 'remove'}] - ) - - def test_baremetal_unset_instance_uuid(self): - arglist = [ - 'node_uuid', - '--instance-uuid', - ] - verifylist = [ - ('node', 'node_uuid'), - ('instance_uuid', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/instance_uuid', 'op': 'remove'}] - ) - - def test_baremetal_unset_name(self): - arglist = [ - 'node_uuid', - '--name', - ] - verifylist = [ - ('node', 'node_uuid'), - ('name', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/name', 'op': 'remove'}] - ) - - def test_baremetal_unset_resource_class(self): - arglist = [ - 'node_uuid', - '--resource-class', - ] - verifylist = [ - ('node', 'node_uuid'), - ('resource_class', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/resource_class', 'op': 'remove'}] - ) - - def test_baremetal_unset_extra(self): - arglist = [ - 'node_uuid', - '--extra', 'foo', - ] - verifylist = [ - ('node', 'node_uuid'), - ('extra', ['foo']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/extra/foo', 'op': 'remove'}] - ) - - def test_baremetal_unset_driver_info(self): - arglist = [ - 'node_uuid', - '--driver-info', 'foo', - ] - verifylist = [ - ('node', 'node_uuid'), - ('driver_info', ['foo']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/driver_info/foo', 'op': 'remove'}] - ) - - def test_baremetal_unset_instance_info(self): - arglist = [ - 'node_uuid', - '--instance-info', 'foo', - ] - verifylist = [ - ('node', 'node_uuid'), - ('instance_info', ['foo']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/instance_info/foo', 'op': 'remove'}] - ) - - def test_baremetal_unset_target_raid_config(self): - arglist = [ - 'node_uuid', - '--target-raid-config', - ] - verifylist = [ - ('node', 'node_uuid'), - ('target_raid_config', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.assertFalse(self.baremetal_mock.node.update.called) - self.baremetal_mock.node.set_target_raid_config.\ - assert_called_once_with('node_uuid', {}) - - def test_baremetal_unset_target_raid_config_and_name(self): - arglist = [ - 'node_uuid', - '--name', - '--target-raid-config', - ] - verifylist = [ - ('node', 'node_uuid'), - ('name', True), - ('target_raid_config', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.set_target_raid_config.\ - assert_called_once_with('node_uuid', {}) - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/name', 'op': 'remove'}] - ) - - def test_baremetal_unset_chassis_uuid(self): - arglist = [ - 'node_uuid', - '--chassis-uuid', - ] - verifylist = [ - ('node', 'node_uuid'), - ('chassis_uuid', True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/chassis_uuid', 'op': 'remove'}] - ) - - def _test_baremetal_unset_hw_interface(self, interface): - arglist = [ - 'node_uuid', - '--%s-interface' % interface, - ] - verifylist = [ - ('node', 'node_uuid'), - ('%s_interface' % interface, True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.update.assert_called_once_with( - 'node_uuid', - [{'path': '/%s_interface' % interface, 'op': 'remove'}] - ) - - def test_baremetal_unset_boot_interface(self): - self._test_baremetal_unset_hw_interface('boot') - - def test_baremetal_unset_console_interface(self): - self._test_baremetal_unset_hw_interface('console') - - def test_baremetal_unset_deploy_interface(self): - self._test_baremetal_unset_hw_interface('deploy') - - def test_baremetal_unset_inspect_interface(self): - self._test_baremetal_unset_hw_interface('inspect') - - def test_baremetal_unset_management_interface(self): - self._test_baremetal_unset_hw_interface('management') - - def test_baremetal_unset_network_interface(self): - self._test_baremetal_unset_hw_interface('network') - - def test_baremetal_unset_power_interface(self): - self._test_baremetal_unset_hw_interface('power') - - def test_baremetal_unset_raid_interface(self): - self._test_baremetal_unset_hw_interface('raid') - - def test_baremetal_unset_storage_interface(self): - self._test_baremetal_unset_hw_interface('storage') - - def test_baremetal_unset_vendor_interface(self): - self._test_baremetal_unset_hw_interface('vendor') - - -class TestValidate(TestBaremetal): - def setUp(self): - super(TestValidate, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.ValidateBaremetalNode(self.app, None) - - self.baremetal_mock.node.validate.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - {'management': {'result': True}, - 'console': {'reason': "Missing 'ipmi_terminal_port'", - 'result': False}, - 'network': {'result': True}, - 'power': {'result': True}, - 'deploy': {'result': True}, - 'inspect': {'reason': "not supported", 'result': None}, - 'boot': {'result': True}, - 'raid': {'result': True}}, - loaded=True, - )) - - def test_baremetal_validate_no_arg(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_validate(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.validate.assert_called_once_with('node_uuid') - - -class TestVifList(TestBaremetal): - def setUp(self): - super(TestVifList, self).setUp() - - self.baremetal_mock.node.vif_list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.VIFS), - loaded=True, - ), - ] - - # Get the command object to test - self.cmd = baremetal_node.VifListBaremetalNode(self.app, None) - - def test_baremetal_vif_list(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.vif_list.assert_called_once_with('node_uuid') - - -class TestVifAttach(TestBaremetal): - def setUp(self): - super(TestVifAttach, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.VifAttachBaremetalNode(self.app, None) - - def test_baremetal_vif_attach(self): - arglist = ['node_uuid', 'aaa-aaa'] - verifylist = [('node', 'node_uuid'), - ('vif_id', 'aaa-aaa')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.vif_attach.assert_called_once_with( - 'node_uuid', 'aaa-aaa') - - def test_baremetal_vif_attach_custom_fields(self): - arglist = ['node_uuid', 'aaa-aaa', '--vif-info', 'foo=bar'] - verifylist = [('node', 'node_uuid'), - ('vif_id', 'aaa-aaa'), - ('vif_info', ['foo=bar'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.vif_attach.assert_called_once_with( - 'node_uuid', 'aaa-aaa', foo='bar') - - -class TestVifDetach(TestBaremetal): - def setUp(self): - super(TestVifDetach, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.VifDetachBaremetalNode(self.app, None) - - def test_baremetal_vif_detach(self): - arglist = ['node_uuid', 'aaa-aaa'] - verifylist = [('node', 'node_uuid'), - ('vif_id', 'aaa-aaa')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.vif_detach.assert_called_once_with( - 'node_uuid', 'aaa-aaa') - - -class TestBaremetalInject(TestBaremetal): - def setUp(self): - super(TestBaremetalInject, self).setUp() - - # Get the command object to test - self.cmd = baremetal_node.InjectNmiBaremetalNode(self.app, None) - - def test_baremetal_inject_no_options(self): - arglist = [] - verifylist = [] - - self.assertRaises(oscutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_inject_nmi_uuid(self): - arglist = ['node_uuid'] - verifylist = [('node', 'node_uuid')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.baremetal_mock.node.inject_nmi.assert_called_once_with( - 'node_uuid') diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_port.py b/ironicclient/tests/unit/osc/v1/test_baremetal_port.py deleted file mode 100644 index ca831d1..0000000 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_port.py +++ /dev/null @@ -1,760 +0,0 @@ -# -# Copyright 2015 Red Hat, Inc. -# -# 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 copy - -import mock -from osc_lib.tests import utils as osctestutils -from osc_lib import utils as oscutils - -from ironicclient import exc -from ironicclient.osc.v1 import baremetal_port -from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes - - -class TestBaremetalPort(baremetal_fakes.TestBaremetal): - - def setUp(self): - super(TestBaremetalPort, self).setUp() - - self.baremetal_mock = self.app.client_manager.baremetal - self.baremetal_mock.reset_mock() - - -class TestCreateBaremetalPort(TestBaremetalPort): - def setUp(self): - super(TestCreateBaremetalPort, self).setUp() - - self.baremetal_mock.port.create.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_PORT), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_port.CreateBaremetalPort(self.app, None) - - def test_baremetal_port_create(self): - arglist = [ - baremetal_fakes.baremetal_port_address, - '--node', baremetal_fakes.baremetal_uuid, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_port_address), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_port_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - } - - self.baremetal_mock.port.create.assert_called_once_with(**args) - - def test_baremetal_port_create_extras(self): - arglist = [ - baremetal_fakes.baremetal_port_address, - '--node', baremetal_fakes.baremetal_uuid, - '--extra', 'key1=value1', - '--extra', 'key2=value2' - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_port_address), - ('extra', ['key1=value1', 'key2=value2']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - args = { - 'address': baremetal_fakes.baremetal_port_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'extra': baremetal_fakes.baremetal_port_extra - } - self.baremetal_mock.port.create.assert_called_once_with(**args) - - def test_baremetal_port_create_no_address(self): - arglist = ['--node', baremetal_fakes.baremetal_uuid] - - verifylist = [('node_uuid', baremetal_fakes.baremetal_uuid)] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_port_create_no_node(self): - arglist = [baremetal_fakes.baremetal_port_address] - - verifylist = [ - ('address', baremetal_fakes.baremetal_port_address) - ] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_port_create_no_args(self): - arglist = [] - verifylist = [] - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_port_create_uuid(self): - port_uuid = "da6c8d2e-fbcd-457a-b2a7-cc5c775933af" - arglist = [ - baremetal_fakes.baremetal_port_address, - '--node', baremetal_fakes.baremetal_uuid, - '--uuid', port_uuid - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_port_address), - ('uuid', port_uuid) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_port_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'uuid': port_uuid - } - - self.baremetal_mock.port.create.assert_called_once_with(**args) - - def _test_baremetal_port_create_llc_warning(self, additional_args, - additional_verify_items): - arglist = [ - baremetal_fakes.baremetal_port_address, - '--node', baremetal_fakes.baremetal_uuid, - ] - arglist.extend(additional_args) - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_port_address), - ] - verifylist.extend(additional_verify_items) - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.log = mock.Mock() - - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_port_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'local_link_connection': {'switch_id': 'aa:bb:cc:dd:ee:ff', - 'port_id': 'eth0'} - } - - self.baremetal_mock.port.create.assert_called_once_with(**args) - self.cmd.log.warning.assert_called() - - def test_baremetal_port_create_llc_warning_some_deprecated(self): - self._test_baremetal_port_create_llc_warning( - additional_args=['-l', 'port_id=eth0', '--local-link-connection', - 'switch_id=aa:bb:cc:dd:ee:ff'], - additional_verify_items=[ - ('local_link_connection_deprecated', ['port_id=eth0']), - ('local_link_connection', ['switch_id=aa:bb:cc:dd:ee:ff'])] - ) - - def test_baremetal_port_create_llc_warning_all_deprecated(self): - self._test_baremetal_port_create_llc_warning( - additional_args=['-l', 'port_id=eth0', '-l', - 'switch_id=aa:bb:cc:dd:ee:ff'], - additional_verify_items=[('local_link_connection_deprecated', - ['port_id=eth0', - 'switch_id=aa:bb:cc:dd:ee:ff'])] - ) - - def test_baremetal_port_create_portgroup_uuid(self): - arglist = [ - baremetal_fakes.baremetal_port_address, - '--node', baremetal_fakes.baremetal_uuid, - '--port-group', baremetal_fakes.baremetal_portgroup_uuid, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_port_address), - ('portgroup_uuid', baremetal_fakes.baremetal_portgroup_uuid) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_port_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'portgroup_uuid': baremetal_fakes.baremetal_portgroup_uuid - } - - self.baremetal_mock.port.create.assert_called_once_with(**args) - - def test_baremetal_port_create_physical_network(self): - arglist = [ - baremetal_fakes.baremetal_port_address, - '--node', baremetal_fakes.baremetal_uuid, - '--physical-network', - baremetal_fakes.baremetal_port_physical_network, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_port_address), - ('physical_network', - baremetal_fakes.baremetal_port_physical_network) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_port_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'physical_network': baremetal_fakes.baremetal_port_physical_network - } - - self.baremetal_mock.port.create.assert_called_once_with(**args) - - -class TestShowBaremetalPort(TestBaremetalPort): - def setUp(self): - super(TestShowBaremetalPort, self).setUp() - - self.baremetal_mock.port.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_PORT), - loaded=True)) - - self.baremetal_mock.port.get_by_address.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_PORT), - loaded=True)) - - self.cmd = baremetal_port.ShowBaremetalPort(self.app, None) - - def test_baremetal_port_show(self): - arglist = ['zzz-zzzzzz-zzzz'] - verifylist = [('port', baremetal_fakes.baremetal_port_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - # Set expected values - args = ['zzz-zzzzzz-zzzz'] - self.baremetal_mock.port.get.assert_called_with(*args, fields=None) - - collist = ( - 'address', - 'extra', - 'node_uuid', - 'uuid') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_port_address, - baremetal_fakes.baremetal_port_extra, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_port_uuid) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_port_show_address(self): - - arglist = ['--address', baremetal_fakes.baremetal_port_address] - verifylist = [('address', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - args = {'AA:BB:CC:DD:EE:FF'} - self.baremetal_mock.port.get_by_address.assert_called_with( - *args, fields=None) - - def test_baremetal_port_show_no_port(self): - arglist = [] - verifylist = [] - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestBaremetalPortUnset(TestBaremetalPort): - def setUp(self): - super(TestBaremetalPortUnset, self).setUp() - - self.baremetal_mock.port.update.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_PORT), - loaded=True)) - - self.cmd = baremetal_port.UnsetBaremetalPort(self.app, None) - - def test_baremetal_port_unset_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_port_unset_no_property(self): - arglist = [baremetal_fakes.baremetal_port_uuid] - verifylist = [('port', baremetal_fakes.baremetal_port_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.assertFalse(self.baremetal_mock.port.update.called) - - def test_baremetal_port_unset_extra(self): - arglist = ['port', '--extra', 'foo'] - verifylist = [('port', 'port'), - ('extra', ['foo'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - 'port', - [{'path': '/extra/foo', 'op': 'remove'}]) - - def test_baremetal_port_unset_multiple_extras(self): - arglist = ['port', - '--extra', 'foo', - '--extra', 'bar'] - verifylist = [('port', 'port'), - ('extra', ['foo', 'bar'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - 'port', - [{'path': '/extra/foo', 'op': 'remove'}, - {'path': '/extra/bar', 'op': 'remove'}]) - - def test_baremetal_port_unset_portgroup_uuid(self): - arglist = ['port', '--port-group'] - verifylist = [('port', 'port'), - ('portgroup', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - 'port', - [{'path': '/portgroup_uuid', 'op': 'remove'}]) - - def test_baremetal_port_unset_physical_network(self): - arglist = ['port', '--physical-network'] - verifylist = [('port', 'port'), - ('physical_network', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - 'port', - [{'path': '/physical_network', 'op': 'remove'}]) - - -class TestBaremetalPortSet(TestBaremetalPort): - def setUp(self): - super(TestBaremetalPortSet, self).setUp() - - self.baremetal_mock.port.update.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_PORT), - loaded=True)) - - self.cmd = baremetal_port.SetBaremetalPort(self.app, None) - - def test_baremetal_port_set_node_uuid(self): - new_node_uuid = '1111-111111-1111' - arglist = [ - baremetal_fakes.baremetal_port_uuid, - '--node', new_node_uuid] - verifylist = [ - ('port', baremetal_fakes.baremetal_port_uuid), - ('node_uuid', new_node_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - baremetal_fakes.baremetal_port_uuid, - [{'path': '/node_uuid', 'value': new_node_uuid, 'op': 'add'}]) - - def test_baremetal_port_set_address(self): - arglist = [ - baremetal_fakes.baremetal_port_uuid, - '--address', baremetal_fakes.baremetal_port_address] - verifylist = [ - ('port', baremetal_fakes.baremetal_port_uuid), - ('address', baremetal_fakes.baremetal_port_address)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - baremetal_fakes.baremetal_port_uuid, - [{'path': '/address', - 'value': baremetal_fakes.baremetal_port_address, - 'op': 'add'}]) - - def test_baremetal_set_extra(self): - arglist = ['port', '--extra', 'foo=bar'] - verifylist = [('port', 'port'), - ('extra', ['foo=bar'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - 'port', - [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}]) - - def test_baremetal_port_set_portgroup_uuid(self): - new_portgroup_uuid = '1111-111111-1111' - arglist = [ - baremetal_fakes.baremetal_port_uuid, - '--port-group', new_portgroup_uuid] - verifylist = [ - ('port', baremetal_fakes.baremetal_port_uuid), - ('portgroup_uuid', new_portgroup_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - baremetal_fakes.baremetal_port_uuid, - [{'path': '/portgroup_uuid', 'value': new_portgroup_uuid, - 'op': 'add'}]) - - def test_baremetal_set_local_link_connection(self): - arglist = [ - baremetal_fakes.baremetal_port_uuid, - '--local-link-connection', 'switch_info=bar'] - verifylist = [('port', baremetal_fakes.baremetal_port_uuid), - ('local_link_connection', ['switch_info=bar'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - baremetal_fakes.baremetal_port_uuid, - [{'path': '/local_link_connection/switch_info', 'value': 'bar', - 'op': 'add'}]) - - def test_baremetal_port_set_pxe_enabled(self): - arglist = [ - baremetal_fakes.baremetal_port_uuid, - '--pxe-enabled'] - verifylist = [ - ('port', baremetal_fakes.baremetal_port_uuid), - ('pxe_enabled', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - baremetal_fakes.baremetal_port_uuid, - [{'path': '/pxe_enabled', 'value': 'True', 'op': 'add'}]) - - def test_baremetal_port_set_pxe_disabled(self): - arglist = [ - baremetal_fakes.baremetal_port_uuid, - '--pxe-disabled'] - verifylist = [ - ('port', baremetal_fakes.baremetal_port_uuid), - ('pxe_enabled', False)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - baremetal_fakes.baremetal_port_uuid, - [{'path': '/pxe_enabled', 'value': 'False', 'op': 'add'}]) - - def test_baremetal_port_set_physical_network(self): - new_physical_network = 'physnet2' - arglist = [ - baremetal_fakes.baremetal_port_uuid, - '--physical-network', new_physical_network] - verifylist = [ - ('port', baremetal_fakes.baremetal_port_uuid), - ('physical_network', new_physical_network)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.port.update.assert_called_once_with( - baremetal_fakes.baremetal_port_uuid, - [{'path': '/physical_network', 'value': new_physical_network, - 'op': 'add'}]) - - def test_baremetal_port_set_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_port_set_no_property(self): - arglist = [baremetal_fakes.baremetal_port_uuid] - verifylist = [('port', baremetal_fakes.baremetal_port_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.assertFalse(self.baremetal_mock.port.update.called) - - -class TestBaremetalPortDelete(TestBaremetalPort): - def setUp(self): - super(TestBaremetalPortDelete, self).setUp() - - self.baremetal_mock.port.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_PORT), - loaded=True)) - - self.cmd = baremetal_port.DeleteBaremetalPort(self.app, None) - - def test_baremetal_port_delete(self): - arglist = ['zzz-zzzzzz-zzzz'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - args = 'zzz-zzzzzz-zzzz' - self.baremetal_mock.port.delete.assert_called_with(args) - - def test_baremetal_port_delete_multiple(self): - arglist = ['zzz-zzzzzz-zzzz', 'fakename'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - args = ['zzz-zzzzzz-zzzz', 'fakename'] - self.baremetal_mock.port.delete.has_calls( - [mock.call(x) for x in args]) - self.assertEqual(2, self.baremetal_mock.port.delete.call_count) - - def test_baremetal_port_delete_multiple_with_fail(self): - arglist = ['zzz-zzzzzz-zzzz', 'badname'] - verifylist = [] - - self.baremetal_mock.port.delete.side_effect = ['', exc.ClientException] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises(exc.ClientException, - self.cmd.take_action, - parsed_args) - - args = ['zzz-zzzzzz-zzzz', 'badname'] - self.baremetal_mock.port.delete.has_calls( - [mock.call(x) for x in args]) - self.assertEqual(2, self.baremetal_mock.port.delete.call_count) - - def test_baremetal_port_delete_no_port(self): - arglist = [] - verifylist = [] - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestBaremetalPortList(TestBaremetalPort): - def setUp(self): - super(TestBaremetalPortList, self).setUp() - - self.baremetal_mock.port.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.BAREMETAL_PORT), - loaded=True) - ] - - self.cmd = baremetal_port.ListBaremetalPort(self.app, None) - - def test_baremetal_port_list(self): - arglist = [] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None} - self.baremetal_mock.port.list.assert_called_with(**kwargs) - - collist = ( - "UUID", - "Address") - self.assertEqual(collist, columns) - - datalist = (( - baremetal_fakes.baremetal_port_uuid, - baremetal_fakes.baremetal_port_address - ), ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_port_list_address(self): - arglist = ['--address', baremetal_fakes.baremetal_port_address] - verifylist = [('address', baremetal_fakes.baremetal_port_address)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'address': baremetal_fakes.baremetal_port_address, - 'marker': None, - 'limit': None, - } - self.baremetal_mock.port.list.assert_called_with(**kwargs) - - def test_baremetal_port_list_node(self): - arglist = ['--node', baremetal_fakes.baremetal_uuid] - verifylist = [('node', baremetal_fakes.baremetal_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'node': baremetal_fakes.baremetal_uuid, - 'marker': None, - 'limit': None, - } - self.baremetal_mock.port.list.assert_called_with(**kwargs) - - def test_baremetal_port_list_portgroup(self): - arglist = ['--port-group', baremetal_fakes.baremetal_portgroup_uuid] - verifylist = [('portgroup', baremetal_fakes.baremetal_portgroup_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - kwargs = { - 'portgroup': baremetal_fakes.baremetal_portgroup_uuid, - 'marker': None, - 'limit': None, - } - self.baremetal_mock.port.list.assert_called_with(**kwargs) - - def test_baremetal_port_list_long(self): - arglist = ['--long'] - verifylist = [('detail', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'detail': True, - 'marker': None, - 'limit': None, - } - self.baremetal_mock.port.list.assert_called_with(**kwargs) - - collist = ('UUID', 'Address', 'Created At', 'Extra', 'Node UUID', - 'Local Link Connection', 'Portgroup UUID', - 'PXE boot enabled', 'Physical Network', 'Updated At', - 'Internal Info') - self.assertEqual(collist, columns) - - datalist = (( - baremetal_fakes.baremetal_port_uuid, - baremetal_fakes.baremetal_port_address, - '', - oscutils.format_dict(baremetal_fakes.baremetal_port_extra), - baremetal_fakes.baremetal_uuid, - '', - '', - '', - '', - '', - '' - ), ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_port_list_fields(self): - arglist = ['--fields', 'uuid', 'address'] - verifylist = [('fields', [['uuid', 'address']])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None, - 'detail': False, - 'fields': ('uuid', 'address') - } - self.baremetal_mock.port.list.assert_called_with(**kwargs) - - def test_baremetal_port_list_fields_multiple(self): - arglist = ['--fields', 'uuid', 'address', '--fields', 'extra'] - verifylist = [('fields', [['uuid', 'address'], ['extra']])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None, - 'detail': False, - 'fields': ('uuid', 'address', 'extra') - } - self.baremetal_mock.port.list.assert_called_with(**kwargs) - - def test_baremetal_port_list_invalid_fields(self): - arglist = ['--fields', 'uuid', 'invalid'] - verifylist = [('fields', [['uuid', 'invalid']])] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_portgroup.py b/ironicclient/tests/unit/osc/v1/test_baremetal_portgroup.py deleted file mode 100644 index a7b0d14..0000000 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_portgroup.py +++ /dev/null @@ -1,747 +0,0 @@ -# -# Copyright 2016 Mirantis, Inc. -# -# 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 copy - -import mock -from osc_lib.tests import utils as osctestutils - -from ironicclient.osc.v1 import baremetal_portgroup -from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes - - -class TestBaremetalPortGroup(baremetal_fakes.TestBaremetal): - - def setUp(self): - super(TestBaremetalPortGroup, self).setUp() - - self.baremetal_mock = self.app.client_manager.baremetal - self.baremetal_mock.reset_mock() - - -class TestCreateBaremetalPortGroup(TestBaremetalPortGroup): - - def setUp(self): - super(TestCreateBaremetalPortGroup, self).setUp() - - self.baremetal_mock.portgroup.create.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.PORTGROUP), - loaded=True, - )) - - # Get the command object to test - self.cmd = baremetal_portgroup.CreateBaremetalPortGroup(self.app, None) - - def test_baremetal_portgroup_create(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'node_uuid': baremetal_fakes.baremetal_uuid, - } - - self.baremetal_mock.portgroup.create.assert_called_once_with(**args) - - def test_baremetal_portgroup_create_name_address_uuid(self): - arglist = [ - '--address', baremetal_fakes.baremetal_portgroup_address, - '--node', baremetal_fakes.baremetal_uuid, - '--name', baremetal_fakes.baremetal_portgroup_name, - '--uuid', baremetal_fakes.baremetal_portgroup_uuid, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_portgroup_address), - ('name', baremetal_fakes.baremetal_portgroup_name), - ('uuid', baremetal_fakes.baremetal_portgroup_uuid), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_portgroup_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'name': baremetal_fakes.baremetal_portgroup_name, - 'uuid': baremetal_fakes.baremetal_portgroup_uuid, - } - - self.baremetal_mock.portgroup.create.assert_called_once_with(**args) - - def test_baremetal_portgroup_create_support_standalone_ports(self): - arglist = [ - '--address', baremetal_fakes.baremetal_portgroup_address, - '--node', baremetal_fakes.baremetal_uuid, - '--support-standalone-ports' - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_portgroup_address), - ('support_standalone_ports', True), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_portgroup_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'standalone_ports_supported': True, - } - - self.baremetal_mock.portgroup.create.assert_called_once_with(**args) - - def test_baremetal_portgroup_create_unsupport_standalone_ports(self): - arglist = [ - '--address', baremetal_fakes.baremetal_portgroup_address, - '--node', baremetal_fakes.baremetal_uuid, - '--unsupport-standalone-ports' - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_portgroup_address), - ('unsupport_standalone_ports', True), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_portgroup_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'standalone_ports_supported': False, - } - - self.baremetal_mock.portgroup.create.assert_called_once_with(**args) - - def test_baremetal_portgroup_create_name_extras(self): - arglist = [ - '--address', baremetal_fakes.baremetal_portgroup_address, - '--node', baremetal_fakes.baremetal_uuid, - '--name', baremetal_fakes.baremetal_portgroup_name, - '--extra', 'key1=value1', - '--extra', 'key2=value2' - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('address', baremetal_fakes.baremetal_portgroup_address), - ('name', baremetal_fakes.baremetal_portgroup_name), - ('extra', ['key1=value1', 'key2=value2']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'address': baremetal_fakes.baremetal_portgroup_address, - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'name': baremetal_fakes.baremetal_portgroup_name, - 'extra': baremetal_fakes.baremetal_portgroup_extra - } - - self.baremetal_mock.portgroup.create.assert_called_once_with(**args) - - def test_baremetal_portgroup_create_mode_properties(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--mode', baremetal_fakes.baremetal_portgroup_mode, - '--property', 'key1=value11', - '--property', 'key2=value22' - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('mode', baremetal_fakes.baremetal_portgroup_mode), - ('properties', ['key1=value11', 'key2=value22']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # DisplayCommandBase.take_action() returns two tuples - self.cmd.take_action(parsed_args) - - # Set expected values - args = { - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'mode': baremetal_fakes.baremetal_portgroup_mode, - 'properties': baremetal_fakes.baremetal_portgroup_properties - } - - self.baremetal_mock.portgroup.create.assert_called_once_with(**args) - - def test_baremetal_portgroup_create_no_options(self): - arglist = [] - verifylist = [] - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestShowBaremetalPortGroup(TestBaremetalPortGroup): - - def setUp(self): - super(TestShowBaremetalPortGroup, self).setUp() - - self.baremetal_mock.portgroup.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.PORTGROUP), - loaded=True)) - - self.baremetal_mock.portgroup.get_by_address.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.PORTGROUP), - loaded=True)) - - self.cmd = baremetal_portgroup.ShowBaremetalPortGroup(self.app, None) - - def test_baremetal_portgroup_show(self): - arglist = ['ppp-gggggg-pppp'] - verifylist = [('portgroup', baremetal_fakes.baremetal_portgroup_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - # Set expected values - args = ['ppp-gggggg-pppp'] - self.baremetal_mock.portgroup.get.assert_called_with(*args, - fields=None) - - collist = ('address', 'extra', 'mode', 'name', 'node_uuid', - 'properties', 'uuid') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_portgroup_address, - baremetal_fakes.baremetal_portgroup_extra, - baremetal_fakes.baremetal_portgroup_mode, - baremetal_fakes.baremetal_portgroup_name, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_portgroup_properties, - baremetal_fakes.baremetal_portgroup_uuid, - ) - - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_portgroup_show_address(self): - arglist = ['--address', baremetal_fakes.baremetal_portgroup_address] - verifylist = [('address', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - args = {baremetal_fakes.baremetal_portgroup_address} - self.baremetal_mock.portgroup.get_by_address.assert_called_with( - *args, fields=None) - - def test_baremetal_portgroup_show_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestBaremetalPortGroupList(TestBaremetalPortGroup): - def setUp(self): - super(TestBaremetalPortGroupList, self).setUp() - - self.baremetal_mock.portgroup.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.PORTGROUP), - loaded=True) - ] - self.cmd = baremetal_portgroup.ListBaremetalPortGroup(self.app, None) - - def test_baremetal_portgroup_list(self): - arglist = [] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None} - self.baremetal_mock.portgroup.list.assert_called_with(**kwargs) - - collist = ( - "UUID", - "Address", - "Name") - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_portgroup_uuid, - baremetal_fakes.baremetal_portgroup_address, - baremetal_fakes.baremetal_portgroup_name),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_portgroup_list_address(self): - arglist = ['--address', baremetal_fakes.baremetal_portgroup_address] - verifylist = [('address', baremetal_fakes.baremetal_portgroup_address)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'address': baremetal_fakes.baremetal_portgroup_address, - 'marker': None, - 'limit': None} - self.baremetal_mock.portgroup.list.assert_called_with(**kwargs) - - collist = ( - "UUID", - "Address", - "Name") - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_portgroup_uuid, - baremetal_fakes.baremetal_portgroup_address, - baremetal_fakes.baremetal_portgroup_name),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_portgroup_list_node(self): - arglist = ['--node', baremetal_fakes.baremetal_uuid] - verifylist = [('node', baremetal_fakes.baremetal_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'node': baremetal_fakes.baremetal_uuid, - 'marker': None, - 'limit': None} - self.baremetal_mock.portgroup.list.assert_called_with(**kwargs) - - collist = ( - "UUID", - "Address", - "Name") - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_portgroup_uuid, - baremetal_fakes.baremetal_portgroup_address, - baremetal_fakes.baremetal_portgroup_name),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_portgroup_list_long(self): - arglist = ['--long'] - verifylist = [('detail', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'detail': True, - 'marker': None, - 'limit': None, - } - self.baremetal_mock.portgroup.list.assert_called_with(**kwargs) - - collist = ('UUID', 'Address', 'Created At', 'Extra', - 'Standalone Ports Supported', 'Node UUID', 'Name', - 'Updated At', 'Internal Info', 'Mode', 'Properties') - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_portgroup_uuid, - baremetal_fakes.baremetal_portgroup_address, - '', - baremetal_fakes.baremetal_portgroup_extra, - '', - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_portgroup_name, - '', - '', - baremetal_fakes.baremetal_portgroup_mode, - baremetal_fakes.baremetal_portgroup_properties),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_portgroup_list_fields(self): - arglist = ['--fields', 'uuid', 'address'] - verifylist = [('fields', [['uuid', 'address']])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None, - 'detail': False, - 'fields': ('uuid', 'address') - } - self.baremetal_mock.portgroup.list.assert_called_with(**kwargs) - - def test_baremetal_portgroup_list_fields_multiple(self): - arglist = ['--fields', 'uuid', 'address', '--fields', 'extra'] - verifylist = [('fields', [['uuid', 'address'], ['extra']])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None, - 'detail': False, - 'fields': ('uuid', 'address', 'extra') - } - self.baremetal_mock.portgroup.list.assert_called_with(**kwargs) - - def test_baremetal_portgroup_list_invalid_fields(self): - arglist = ['--fields', 'uuid', 'invalid'] - verifylist = [('fields', [['uuid', 'invalid']])] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestBaremetalPortGroupDelete(TestBaremetalPortGroup): - - def setUp(self): - super(TestBaremetalPortGroupDelete, self).setUp() - - self.baremetal_mock.portgroup.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.PORTGROUP), - loaded=True)) - - self.cmd = baremetal_portgroup.DeleteBaremetalPortGroup(self.app, None) - - def test_baremetal_portgroup_delete(self): - arglist = [baremetal_fakes.baremetal_portgroup_uuid] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - args = baremetal_fakes.baremetal_portgroup_uuid - self.baremetal_mock.portgroup.delete.assert_called_with(args) - - def test_baremetal_portgroup_delete_multiple(self): - arglist = [baremetal_fakes.baremetal_portgroup_uuid, - baremetal_fakes.baremetal_portgroup_name] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - args = [baremetal_fakes.baremetal_portgroup_uuid, - baremetal_fakes.baremetal_portgroup_name] - self.baremetal_mock.portgroup.delete.has_calls( - [mock.call(x) for x in args]) - self.assertEqual(2, self.baremetal_mock.portgroup.delete.call_count) - - def test_baremetal_portgroup_delete_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestBaremetalPortGroupSet(TestBaremetalPortGroup): - def setUp(self): - super(TestBaremetalPortGroupSet, self).setUp() - - self.baremetal_mock.portgroup.update.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.PORTGROUP), - loaded=True)) - - self.cmd = baremetal_portgroup.SetBaremetalPortGroup(self.app, None) - - def test_baremetal_portgroup_set_name(self): - new_portgroup_name = 'New-Portgroup-name' - arglist = [ - baremetal_fakes.baremetal_portgroup_uuid, - '--name', new_portgroup_name] - verifylist = [ - ('portgroup', baremetal_fakes.baremetal_portgroup_uuid), - ('name', new_portgroup_name)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - baremetal_fakes.baremetal_portgroup_uuid, - [{'path': '/name', 'value': new_portgroup_name, 'op': 'add'}]) - - def test_baremetal_portgroup_set_address(self): - new_portgroup_address = '00:22:44:66:88:00' - arglist = [ - baremetal_fakes.baremetal_portgroup_uuid, - '--address', new_portgroup_address] - verifylist = [ - ('portgroup', baremetal_fakes.baremetal_portgroup_uuid), - ('address', new_portgroup_address)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - baremetal_fakes.baremetal_portgroup_uuid, - [{'path': '/address', 'value': new_portgroup_address, - 'op': 'add'}]) - - def test_baremetal_portgroup_set_mode(self): - new_portgroup_mode = '802.3ad' - arglist = [ - baremetal_fakes.baremetal_portgroup_uuid, - '--mode', new_portgroup_mode] - verifylist = [ - ('portgroup', baremetal_fakes.baremetal_portgroup_uuid), - ('mode', new_portgroup_mode)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - baremetal_fakes.baremetal_portgroup_uuid, - [{'path': '/mode', 'value': new_portgroup_mode, - 'op': 'add'}]) - - def test_baremetal_portgroup_set_node_uuid(self): - new_node_uuid = 'nnnnnn-uuuuuuuu' - arglist = [ - baremetal_fakes.baremetal_portgroup_uuid, - '--node', new_node_uuid] - verifylist = [ - ('portgroup', baremetal_fakes.baremetal_portgroup_uuid), - ('node_uuid', new_node_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - baremetal_fakes.baremetal_portgroup_uuid, - [{'path': '/node_uuid', 'value': new_node_uuid, - 'op': 'add'}]) - - def test_baremetal_portgroup_set_support_standalone_ports(self): - arglist = [ - baremetal_fakes.baremetal_portgroup_uuid, - '--support-standalone-ports'] - verifylist = [ - ('portgroup', baremetal_fakes.baremetal_portgroup_uuid), - ('support_standalone_ports', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - baremetal_fakes.baremetal_portgroup_uuid, - [{'path': '/standalone_ports_supported', 'value': 'True', - 'op': 'add'}]) - - def test_baremetal_portgroup_set_unsupport_standalone_ports(self): - arglist = [ - baremetal_fakes.baremetal_portgroup_uuid, - '--unsupport-standalone-ports'] - verifylist = [ - ('portgroup', baremetal_fakes.baremetal_portgroup_uuid), - ('unsupport_standalone_ports', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - baremetal_fakes.baremetal_portgroup_uuid, - [{'path': '/standalone_ports_supported', 'value': 'False', - 'op': 'add'}]) - - def test_baremetal_set_extra(self): - arglist = ['portgroup', '--extra', 'foo=bar'] - verifylist = [('portgroup', 'portgroup'), - ('extra', ['foo=bar'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - 'portgroup', - [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}]) - - def test_baremetal_portgroup_set_multiple_extras(self): - arglist = ['portgroup', - '--extra', 'key1=val1', - '--extra', 'key2=val2'] - verifylist = [('portgroup', 'portgroup'), - ('extra', ['key1=val1', 'key2=val2'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - 'portgroup', - [{'path': '/extra/key1', 'value': 'val1', 'op': 'add'}, - {'path': '/extra/key2', 'value': 'val2', 'op': 'add'}]) - - def test_baremetal_portgroup_set_multiple_properties(self): - arglist = ['portgroup', - '--property', 'key3=val3', - '--property', 'key4=val4'] - verifylist = [('portgroup', 'portgroup'), - ('properties', ['key3=val3', 'key4=val4'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - 'portgroup', - [{'path': '/properties/key3', 'value': 'val3', 'op': 'add'}, - {'path': '/properties/key4', 'value': 'val4', 'op': 'add'}]) - - def test_baremetal_portgroup_set_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_portgroup_set_no_property(self): - uuid = baremetal_fakes.baremetal_portgroup_uuid - arglist = [uuid] - verifylist = [('portgroup', uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.assertFalse(self.baremetal_mock.portgroup.update.called) - - -class TestBaremetalPortGroupUnset(TestBaremetalPortGroup): - def setUp(self): - super(TestBaremetalPortGroupUnset, self).setUp() - - self.baremetal_mock.portgroup.update.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.PORTGROUP), - loaded=True)) - - self.cmd = baremetal_portgroup.UnsetBaremetalPortGroup(self.app, None) - - def test_baremetal_portgroup_unset_extra(self): - arglist = ['portgroup', '--extra', 'key1'] - verifylist = [('portgroup', 'portgroup'), - ('extra', ['key1'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - 'portgroup', - [{'path': '/extra/key1', 'op': 'remove'}]) - - def test_baremetal_portgroup_unset_name(self): - arglist = ['portgroup', '--name'] - verifylist = [('name', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - 'portgroup', - [{'path': '/name', 'op': 'remove'}]) - - def test_baremetal_portgroup_unset_address(self): - arglist = ['portgroup', '--address'] - verifylist = [('address', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - 'portgroup', - [{'path': '/address', 'op': 'remove'}]) - - def test_baremetal_portgroup_unset_multiple_extras(self): - arglist = ['portgroup', - '--extra', 'key1', - '--extra', 'key2'] - verifylist = [('portgroup', 'portgroup'), - ('extra', ['key1', 'key2'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - 'portgroup', - [{'path': '/extra/key1', 'op': 'remove'}, - {'path': '/extra/key2', 'op': 'remove'}]) - - def test_baremetal_portgroup_unset_multiple_properties(self): - arglist = ['portgroup', - '--property', 'key1', - '--property', 'key2'] - verifylist = [('portgroup', 'portgroup'), - ('properties', ['key1', 'key2'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.portgroup.update.assert_called_once_with( - 'portgroup', - [{'path': '/properties/key1', 'op': 'remove'}, - {'path': '/properties/key2', 'op': 'remove'}]) - - def test_baremetal_portgroup_unset_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_portgroup_unset_no_property(self): - uuid = baremetal_fakes.baremetal_portgroup_uuid - arglist = [uuid] - verifylist = [('portgroup', uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.assertFalse(self.baremetal_mock.portgroup.update.called) diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_volume_connector.py b/ironicclient/tests/unit/osc/v1/test_baremetal_volume_connector.py deleted file mode 100644 index 8c7b7b7..0000000 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_volume_connector.py +++ /dev/null @@ -1,813 +0,0 @@ -# Copyright 2017 FUJITSU LIMITED -# -# 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 copy - -import mock -from osc_lib.tests import utils as osctestutils - -from ironicclient import exc -from ironicclient.osc.v1 import baremetal_volume_connector as bm_vol_connector -from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes - - -class TestBaremetalVolumeConnector(baremetal_fakes.TestBaremetal): - - def setUp(self): - super(TestBaremetalVolumeConnector, self).setUp() - - self.baremetal_mock = self.app.client_manager.baremetal - self.baremetal_mock.reset_mock() - - -class TestCreateBaremetalVolumeConnector(TestBaremetalVolumeConnector): - - def setUp(self): - super(TestCreateBaremetalVolumeConnector, self).setUp() - - self.baremetal_mock.volume_connector.create.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.VOLUME_CONNECTOR), - loaded=True, - )) - - # Get the command object to test - self.cmd = ( - bm_vol_connector.CreateBaremetalVolumeConnector(self.app, None)) - - def test_baremetal_volume_connector_create(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', baremetal_fakes.baremetal_volume_connector_type, - '--connector-id', - baremetal_fakes.baremetal_volume_connector_connector_id, - '--uuid', baremetal_fakes.baremetal_volume_connector_uuid, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('type', baremetal_fakes.baremetal_volume_connector_type), - ('connector_id', - baremetal_fakes.baremetal_volume_connector_connector_id), - ('uuid', baremetal_fakes.baremetal_volume_connector_uuid), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - args = { - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'type': baremetal_fakes.baremetal_volume_connector_type, - 'connector_id': - baremetal_fakes.baremetal_volume_connector_connector_id, - 'uuid': baremetal_fakes.baremetal_volume_connector_uuid, - } - - self.baremetal_mock.volume_connector.create.assert_called_once_with( - **args) - - def test_baremetal_volume_connector_create_without_uuid(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', baremetal_fakes.baremetal_volume_connector_type, - '--connector-id', - baremetal_fakes.baremetal_volume_connector_connector_id, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('type', baremetal_fakes.baremetal_volume_connector_type), - ('connector_id', - baremetal_fakes.baremetal_volume_connector_connector_id), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - args = { - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'type': baremetal_fakes.baremetal_volume_connector_type, - 'connector_id': - baremetal_fakes.baremetal_volume_connector_connector_id, - } - - self.baremetal_mock.volume_connector.create.assert_called_once_with( - **args) - - def test_baremetal_volume_connector_create_extras(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', baremetal_fakes.baremetal_volume_connector_type, - '--connector-id', - baremetal_fakes.baremetal_volume_connector_connector_id, - '--extra', 'key1=value1', - '--extra', 'key2=value2', - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('type', baremetal_fakes.baremetal_volume_connector_type), - ('connector_id', - baremetal_fakes.baremetal_volume_connector_connector_id), - ('extra', ['key1=value1', 'key2=value2']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - args = { - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'type': baremetal_fakes.baremetal_volume_connector_type, - 'connector_id': - baremetal_fakes.baremetal_volume_connector_connector_id, - 'extra': baremetal_fakes.baremetal_volume_connector_extra, - } - - self.baremetal_mock.volume_connector.create.assert_called_once_with( - **args) - - def test_baremetal_volume_connector_create_invalid_type(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', 'invalid', - '--connector-id', - baremetal_fakes.baremetal_volume_connector_connector_id, - '--uuid', baremetal_fakes.baremetal_volume_connector_uuid, - ] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_create_missing_node(self): - arglist = [ - '--type', baremetal_fakes.baremetal_volume_connector_type, - '--connector-id', - baremetal_fakes.baremetal_volume_connector_connector_id, - '--uuid', baremetal_fakes.baremetal_volume_connector_uuid, - ] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_create_missing_type(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--connector-id', - baremetal_fakes.baremetal_volume_connector_connector_id, - '--uuid', baremetal_fakes.baremetal_volume_connector_uuid, - ] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_create_missing_connector_id(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', baremetal_fakes.baremetal_volume_connector_type, - '--uuid', baremetal_fakes.baremetal_volume_connector_uuid, - ] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestShowBaremetalVolumeConnector(TestBaremetalVolumeConnector): - - def setUp(self): - super(TestShowBaremetalVolumeConnector, self).setUp() - - self.baremetal_mock.volume_connector.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.VOLUME_CONNECTOR), - loaded=True)) - - self.cmd = ( - bm_vol_connector.ShowBaremetalVolumeConnector(self.app, None)) - - def test_baremetal_volume_connector_show(self): - arglist = ['vvv-cccccc-vvvv'] - verifylist = [('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - args = ['vvv-cccccc-vvvv'] - self.baremetal_mock.volume_connector.get.assert_called_once_with( - *args, fields=None) - collist = ('connector_id', 'extra', 'node_uuid', 'type', 'uuid') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_volume_connector_connector_id, - baremetal_fakes.baremetal_volume_connector_extra, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_volume_connector_type, - baremetal_fakes.baremetal_volume_connector_uuid, - ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_connector_show_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_show_fields(self): - arglist = ['vvv-cccccc-vvvv', '--fields', 'uuid', 'connector_id'] - verifylist = [('fields', [['uuid', 'connector_id']]), - ('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid)] - - fake_vc = copy.deepcopy(baremetal_fakes.VOLUME_CONNECTOR) - fake_vc.pop('type') - fake_vc.pop('extra') - fake_vc.pop('node_uuid') - self.baremetal_mock.volume_connector.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - fake_vc, - loaded=True)) - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - args = ['vvv-cccccc-vvvv'] - fields = ['uuid', 'connector_id'] - self.baremetal_mock.volume_connector.get.assert_called_once_with( - *args, fields=fields) - collist = ('connector_id', 'uuid') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_volume_connector_connector_id, - baremetal_fakes.baremetal_volume_connector_uuid, - ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_connector_show_fields_multiple(self): - arglist = ['vvv-cccccc-vvvv', '--fields', 'uuid', 'connector_id', - '--fields', 'type'] - verifylist = [('fields', [['uuid', 'connector_id'], ['type']]), - ('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid)] - - fake_vc = copy.deepcopy(baremetal_fakes.VOLUME_CONNECTOR) - fake_vc.pop('extra') - fake_vc.pop('node_uuid') - self.baremetal_mock.volume_connector.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - fake_vc, - loaded=True)) - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - args = ['vvv-cccccc-vvvv'] - fields = ['uuid', 'connector_id', 'type'] - self.baremetal_mock.volume_connector.get.assert_called_once_with( - *args, fields=fields) - collist = ('connector_id', 'type', 'uuid') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_volume_connector_connector_id, - baremetal_fakes.baremetal_volume_connector_type, - baremetal_fakes.baremetal_volume_connector_uuid, - ) - self.assertEqual(datalist, tuple(data)) - - -class TestListBaremetalVolumeConnector(TestBaremetalVolumeConnector): - def setUp(self): - super(TestListBaremetalVolumeConnector, self).setUp() - - self.baremetal_mock.volume_connector.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.VOLUME_CONNECTOR), - loaded=True) - ] - self.cmd = ( - bm_vol_connector.ListBaremetalVolumeConnector(self.app, None)) - - def test_baremetal_volume_connector_list(self): - arglist = [] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None} - self.baremetal_mock.volume_connector.list.assert_called_once_with( - **kwargs) - - collist = ( - "UUID", - "Node UUID", - "Type", - "Connector ID") - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_connector_uuid, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_volume_connector_type, - baremetal_fakes.baremetal_volume_connector_connector_id),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_connector_list_node(self): - arglist = ['--node', baremetal_fakes.baremetal_uuid] - verifylist = [('node', baremetal_fakes.baremetal_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'node': baremetal_fakes.baremetal_uuid, - 'marker': None, - 'limit': None} - self.baremetal_mock.volume_connector.list.assert_called_once_with( - **kwargs) - - collist = ( - "UUID", - "Node UUID", - "Type", - "Connector ID") - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_connector_uuid, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_volume_connector_type, - baremetal_fakes.baremetal_volume_connector_connector_id),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_connector_list_long(self): - arglist = ['--long'] - verifylist = [('detail', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'detail': True, - 'marker': None, - 'limit': None, - } - self.baremetal_mock.volume_connector.list.assert_called_with(**kwargs) - - collist = ('UUID', 'Node UUID', 'Type', 'Connector ID', 'Extra', - 'Created At', 'Updated At') - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_connector_uuid, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_volume_connector_type, - baremetal_fakes.baremetal_volume_connector_connector_id, - baremetal_fakes.baremetal_volume_connector_extra, - '', - ''),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_connector_list_fields(self): - arglist = ['--fields', 'uuid', 'connector_id'] - verifylist = [('fields', [['uuid', 'connector_id']])] - - fake_vc = copy.deepcopy(baremetal_fakes.VOLUME_CONNECTOR) - fake_vc.pop('type') - fake_vc.pop('extra') - fake_vc.pop('node_uuid') - self.baremetal_mock.volume_connector.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - fake_vc, - loaded=True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'detail': False, - 'marker': None, - 'limit': None, - 'fields': ('uuid', 'connector_id') - } - self.baremetal_mock.volume_connector.list.assert_called_with(**kwargs) - - collist = ('UUID', 'Connector ID') - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_connector_uuid, - baremetal_fakes.baremetal_volume_connector_connector_id),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_connector_list_fields_multiple(self): - arglist = ['--fields', 'uuid', 'connector_id', '--fields', 'extra'] - verifylist = [('fields', [['uuid', 'connector_id'], ['extra']])] - - fake_vc = copy.deepcopy(baremetal_fakes.VOLUME_CONNECTOR) - fake_vc.pop('type') - fake_vc.pop('node_uuid') - self.baremetal_mock.volume_connector.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - fake_vc, - loaded=True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'detail': False, - 'marker': None, - 'limit': None, - 'fields': ('uuid', 'connector_id', 'extra') - } - self.baremetal_mock.volume_connector.list.assert_called_with(**kwargs) - - collist = ('UUID', 'Connector ID', 'Extra') - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_connector_uuid, - baremetal_fakes.baremetal_volume_connector_connector_id, - baremetal_fakes.baremetal_volume_connector_extra),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_connector_list_invalid_fields(self): - arglist = ['--fields', 'uuid', 'invalid'] - verifylist = [('fields', [['uuid', 'invalid']])] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_list_marker(self): - arglist = ['--marker', baremetal_fakes.baremetal_volume_connector_uuid] - verifylist = [ - ('marker', baremetal_fakes.baremetal_volume_connector_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': baremetal_fakes.baremetal_volume_connector_uuid, - 'limit': None} - self.baremetal_mock.volume_connector.list.assert_called_once_with( - **kwargs) - - def test_baremetal_volume_connector_list_limit(self): - arglist = ['--limit', '10'] - verifylist = [('limit', 10)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': 10} - self.baremetal_mock.volume_connector.list.assert_called_once_with( - **kwargs) - - def test_baremetal_volume_connector_list_sort(self): - arglist = ['--sort', 'type'] - verifylist = [('sort', 'type')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None} - self.baremetal_mock.volume_connector.list.assert_called_once_with( - **kwargs) - - def test_baremetal_volume_connector_list_sort_desc(self): - arglist = ['--sort', 'type:desc'] - verifylist = [('sort', 'type:desc')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None} - self.baremetal_mock.volume_connector.list.assert_called_once_with( - **kwargs) - - def test_baremetal_volume_connector_list_exclusive_options(self): - arglist = ['--fields', 'uuid', '--long'] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, []) - - def test_baremetal_volume_connector_list_negative_limit(self): - arglist = ['--limit', '-1'] - verifylist = [('limit', -1)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - - -class TestDeleteBaremetalVolumeConnector(TestBaremetalVolumeConnector): - - def setUp(self): - super(TestDeleteBaremetalVolumeConnector, self).setUp() - - self.cmd = ( - bm_vol_connector.DeleteBaremetalVolumeConnector(self.app, None)) - - def test_baremetal_volume_connector_delete(self): - arglist = [baremetal_fakes.baremetal_volume_connector_uuid] - verifylist = [('volume_connectors', - [baremetal_fakes.baremetal_volume_connector_uuid])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.baremetal_mock.volume_connector.delete.assert_called_with( - baremetal_fakes.baremetal_volume_connector_uuid) - - def test_baremetal_volume_connector_delete_multiple(self): - fake_volume_connector_uuid2 = 'vvv-cccccc-cccc' - arglist = [baremetal_fakes.baremetal_volume_connector_uuid, - fake_volume_connector_uuid2] - verifylist = [('volume_connectors', - [baremetal_fakes.baremetal_volume_connector_uuid, - fake_volume_connector_uuid2])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.baremetal_mock.volume_connector.delete.has_calls( - [mock.call(baremetal_fakes.baremetal_volume_connector_uuid), - mock.call(fake_volume_connector_uuid2)]) - self.assertEqual( - 2, self.baremetal_mock.volume_connector.delete.call_count) - - def test_baremetal_volume_connector_delete_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_delete_error(self): - arglist = [baremetal_fakes.baremetal_volume_connector_uuid] - verifylist = [('volume_connectors', - [baremetal_fakes.baremetal_volume_connector_uuid])] - - self.baremetal_mock.volume_connector.delete.side_effect = ( - exc.NotFound()) - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises(exc.ClientException, - self.cmd.take_action, - parsed_args) - self.baremetal_mock.volume_connector.delete.assert_called_with( - baremetal_fakes.baremetal_volume_connector_uuid) - - def test_baremetal_volume_connector_delete_multiple_error(self): - fake_volume_connector_uuid2 = 'vvv-cccccc-cccc' - arglist = [baremetal_fakes.baremetal_volume_connector_uuid, - fake_volume_connector_uuid2] - verifylist = [('volume_connectors', - [baremetal_fakes.baremetal_volume_connector_uuid, - fake_volume_connector_uuid2])] - - self.baremetal_mock.volume_connector.delete.side_effect = [ - None, exc.NotFound()] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises(exc.ClientException, - self.cmd.take_action, - parsed_args) - - self.baremetal_mock.volume_connector.delete.has_calls( - [mock.call(baremetal_fakes.baremetal_volume_connector_uuid), - mock.call(fake_volume_connector_uuid2)]) - self.assertEqual( - 2, self.baremetal_mock.volume_connector.delete.call_count) - - -class TestSetBaremetalVolumeConnector(TestBaremetalVolumeConnector): - def setUp(self): - super(TestSetBaremetalVolumeConnector, self).setUp() - - self.cmd = ( - bm_vol_connector.SetBaremetalVolumeConnector(self.app, None)) - - def test_baremetal_volume_connector_set_node_uuid(self): - new_node_uuid = 'xxx-xxxxxx-zzzz' - arglist = [ - baremetal_fakes.baremetal_volume_connector_uuid, - '--node', new_node_uuid] - verifylist = [ - ('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid), - ('node_uuid', new_node_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_connector_uuid, - [{'path': '/node_uuid', 'value': new_node_uuid, 'op': 'add'}]) - - def test_baremetal_volume_connector_set_type(self): - new_type = 'wwnn' - arglist = [ - baremetal_fakes.baremetal_volume_connector_uuid, - '--type', new_type] - verifylist = [ - ('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid), - ('type', new_type)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_connector_uuid, - [{'path': '/type', 'value': new_type, 'op': 'add'}]) - - def test_baremetal_volume_connector_set_invalid_type(self): - new_type = 'invalid' - arglist = [ - baremetal_fakes.baremetal_volume_connector_uuid, - '--type', new_type] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_set_connector_id(self): - new_conn_id = '11:22:33:44:55:66:77:88' - arglist = [ - baremetal_fakes.baremetal_volume_connector_uuid, - '--connector-id', new_conn_id] - verifylist = [ - ('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid), - ('connector_id', new_conn_id)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_connector_uuid, - [{'path': '/connector_id', 'value': new_conn_id, 'op': 'add'}]) - - def test_baremetal_volume_connector_set_type_and_connector_id(self): - new_type = 'wwnn' - new_conn_id = '11:22:33:44:55:66:77:88' - arglist = [ - baremetal_fakes.baremetal_volume_connector_uuid, - '--type', new_type, - '--connector-id', new_conn_id] - verifylist = [ - ('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid), - ('type', new_type), - ('connector_id', new_conn_id)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_connector_uuid, - [{'path': '/type', 'value': new_type, 'op': 'add'}, - {'path': '/connector_id', 'value': new_conn_id, 'op': 'add'}]) - - def test_baremetal_volume_connector_set_extra(self): - arglist = [ - baremetal_fakes.baremetal_volume_connector_uuid, - '--extra', 'foo=bar'] - verifylist = [ - ('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid), - ('extra', ['foo=bar'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_connector_uuid, - [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}]) - - def test_baremetal_volume_connector_set_multiple_extras(self): - arglist = [ - baremetal_fakes.baremetal_volume_connector_uuid, - '--extra', 'key1=val1', '--extra', 'key2=val2'] - verifylist = [ - ('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid), - ('extra', ['key1=val1', 'key2=val2'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_connector_uuid, - [{'path': '/extra/key1', 'value': 'val1', 'op': 'add'}, - {'path': '/extra/key2', 'value': 'val2', 'op': 'add'}]) - - def test_baremetal_volume_connector_set_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_set_no_property(self): - arglist = [baremetal_fakes.baremetal_volume_connector_uuid] - verifylist = [('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_not_called() - - -class TestUnsetBaremetalVolumeConnector(TestBaremetalVolumeConnector): - def setUp(self): - super(TestUnsetBaremetalVolumeConnector, self).setUp() - - self.cmd = ( - bm_vol_connector.UnsetBaremetalVolumeConnector(self.app, None)) - - def test_baremetal_volume_connector_unset_extra(self): - arglist = [baremetal_fakes.baremetal_volume_connector_uuid, - '--extra', 'key1'] - verifylist = [('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid), - ('extra', ['key1'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_connector_uuid, - [{'path': '/extra/key1', 'op': 'remove'}]) - - def test_baremetal_volume_connector_unset_multiple_extras(self): - arglist = [baremetal_fakes.baremetal_volume_connector_uuid, - '--extra', 'key1', '--extra', 'key2'] - verifylist = [('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid), - ('extra', ['key1', 'key2'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_connector_uuid, - [{'path': '/extra/key1', 'op': 'remove'}, - {'path': '/extra/key2', 'op': 'remove'}]) - - def test_baremetal_volume_connector_unset_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_connector_unset_no_property(self): - arglist = [baremetal_fakes.baremetal_volume_connector_uuid] - verifylist = [('volume_connector', - baremetal_fakes.baremetal_volume_connector_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_connector.update.assert_not_called() diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_volume_target.py b/ironicclient/tests/unit/osc/v1/test_baremetal_volume_target.py deleted file mode 100644 index 3208eaf..0000000 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_volume_target.py +++ /dev/null @@ -1,977 +0,0 @@ -# Copyright 2017 FUJITSU LIMITED -# -# 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 copy - -import mock -from osc_lib.tests import utils as osctestutils - -from ironicclient import exc -from ironicclient.osc.v1 import baremetal_volume_target as bm_vol_target -from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes - - -class TestBaremetalVolumeTarget(baremetal_fakes.TestBaremetal): - - def setUp(self): - super(TestBaremetalVolumeTarget, self).setUp() - - self.baremetal_mock = self.app.client_manager.baremetal - self.baremetal_mock.reset_mock() - - -class TestCreateBaremetalVolumeTarget(TestBaremetalVolumeTarget): - - def setUp(self): - super(TestCreateBaremetalVolumeTarget, self).setUp() - - self.baremetal_mock.volume_target.create.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.VOLUME_TARGET), - loaded=True, - )) - - # Get the command object to test - self.cmd = ( - bm_vol_target.CreateBaremetalVolumeTarget(self.app, None)) - - def test_baremetal_volume_target_create(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', - baremetal_fakes.baremetal_volume_target_volume_type, - '--boot-index', - baremetal_fakes.baremetal_volume_target_boot_index, - '--volume-id', - baremetal_fakes.baremetal_volume_target_volume_id, - '--uuid', baremetal_fakes.baremetal_volume_target_uuid, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('volume_type', - baremetal_fakes.baremetal_volume_target_volume_type), - ('boot_index', - baremetal_fakes.baremetal_volume_target_boot_index), - ('volume_id', - baremetal_fakes.baremetal_volume_target_volume_id), - ('uuid', baremetal_fakes.baremetal_volume_target_uuid), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - args = { - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'volume_type': - baremetal_fakes.baremetal_volume_target_volume_type, - 'boot_index': - baremetal_fakes.baremetal_volume_target_boot_index, - 'volume_id': - baremetal_fakes.baremetal_volume_target_volume_id, - 'uuid': baremetal_fakes.baremetal_volume_target_uuid, - } - - self.baremetal_mock.volume_target.create.assert_called_once_with( - **args) - - def test_baremetal_volume_target_create_without_uuid(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', - baremetal_fakes.baremetal_volume_target_volume_type, - '--boot-index', - baremetal_fakes.baremetal_volume_target_boot_index, - '--volume-id', - baremetal_fakes.baremetal_volume_target_volume_id, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('volume_type', - baremetal_fakes.baremetal_volume_target_volume_type), - ('boot_index', - baremetal_fakes.baremetal_volume_target_boot_index), - ('volume_id', - baremetal_fakes.baremetal_volume_target_volume_id), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - args = { - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'volume_type': - baremetal_fakes.baremetal_volume_target_volume_type, - 'boot_index': - baremetal_fakes.baremetal_volume_target_boot_index, - 'volume_id': - baremetal_fakes.baremetal_volume_target_volume_id, - } - - self.baremetal_mock.volume_target.create.assert_called_once_with( - **args) - - def test_baremetal_volume_target_create_extras(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', - baremetal_fakes.baremetal_volume_target_volume_type, - '--boot-index', - baremetal_fakes.baremetal_volume_target_boot_index, - '--volume-id', - baremetal_fakes.baremetal_volume_target_volume_id, - '--extra', 'key1=value1', - '--extra', 'key2=value2', - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('volume_type', - baremetal_fakes.baremetal_volume_target_volume_type), - ('boot_index', - baremetal_fakes.baremetal_volume_target_boot_index), - ('volume_id', - baremetal_fakes.baremetal_volume_target_volume_id), - ('extra', ['key1=value1', 'key2=value2']) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - args = { - 'node_uuid': baremetal_fakes.baremetal_uuid, - 'volume_type': - baremetal_fakes.baremetal_volume_target_volume_type, - 'boot_index': - baremetal_fakes.baremetal_volume_target_boot_index, - 'volume_id': - baremetal_fakes.baremetal_volume_target_volume_id, - 'extra': baremetal_fakes.baremetal_volume_target_extra, - } - - self.baremetal_mock.volume_target.create.assert_called_once_with( - **args) - - def _test_baremetal_volume_target_missing_param(self, missing): - argdict = { - '--node': baremetal_fakes.baremetal_uuid, - '--type': - baremetal_fakes.baremetal_volume_target_volume_type, - '--boot-index': - baremetal_fakes.baremetal_volume_target_boot_index, - '--volume-id': - baremetal_fakes.baremetal_volume_target_volume_id, - '--uuid': baremetal_fakes.baremetal_volume_target_uuid, - } - - arglist = [] - for k, v in argdict.items(): - if k not in missing: - arglist += [k, v] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_target_create_missing_node(self): - self._test_baremetal_volume_target_missing_param(['--node']) - - def test_baremetal_volume_target_create_missing_type(self): - self._test_baremetal_volume_target_missing_param(['--type']) - - def test_baremetal_volume_target_create_missing_boot_index(self): - self._test_baremetal_volume_target_missing_param(['--boot-index']) - - def test_baremetal_volume_target_create_missing_volume_id(self): - self._test_baremetal_volume_target_missing_param(['--volume-id']) - - def test_baremetal_volume_target_create_invalid_boot_index(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', - baremetal_fakes.baremetal_volume_target_volume_type, - '--boot-index', 'string', - '--volume-id', - baremetal_fakes.baremetal_volume_target_volume_id, - ] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_target_create_negative_boot_index(self): - arglist = [ - '--node', baremetal_fakes.baremetal_uuid, - '--type', - baremetal_fakes.baremetal_volume_target_volume_type, - '--boot-index', '-1', - '--volume-id', - baremetal_fakes.baremetal_volume_target_volume_id, - ] - - verifylist = [ - ('node_uuid', baremetal_fakes.baremetal_uuid), - ('volume_type', - baremetal_fakes.baremetal_volume_target_volume_type), - ('boot_index', -1), - ('volume_id', - baremetal_fakes.baremetal_volume_target_volume_id), - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) - - -class TestShowBaremetalVolumeTarget(TestBaremetalVolumeTarget): - - def setUp(self): - super(TestShowBaremetalVolumeTarget, self).setUp() - - self.baremetal_mock.volume_target.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.VOLUME_TARGET), - loaded=True)) - - self.cmd = ( - bm_vol_target.ShowBaremetalVolumeTarget(self.app, None)) - - def test_baremetal_volume_target_show(self): - arglist = ['vvv-tttttt-vvvv'] - verifylist = [('volume_target', - baremetal_fakes.baremetal_volume_target_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - args = ['vvv-tttttt-vvvv'] - self.baremetal_mock.volume_target.get.assert_called_once_with( - *args, fields=None) - collist = ('boot_index', 'extra', 'node_uuid', 'properties', 'uuid', - 'volume_id', 'volume_type') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_volume_target_boot_index, - baremetal_fakes.baremetal_volume_target_extra, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_volume_target_properties, - baremetal_fakes.baremetal_volume_target_uuid, - baremetal_fakes.baremetal_volume_target_volume_id, - baremetal_fakes.baremetal_volume_target_volume_type, - ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_target_show_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_target_show_fields(self): - arglist = ['vvv-tttttt-vvvv', '--fields', 'uuid', 'volume_id'] - verifylist = [('fields', [['uuid', 'volume_id']]), - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid)] - - fake_vt = copy.deepcopy(baremetal_fakes.VOLUME_TARGET) - fake_vt.pop('node_uuid') - fake_vt.pop('volume_type') - fake_vt.pop('boot_index') - fake_vt.pop('extra') - fake_vt.pop('properties') - self.baremetal_mock.volume_target.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - fake_vt, - loaded=True)) - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - args = ['vvv-tttttt-vvvv'] - fields = ['uuid', 'volume_id'] - self.baremetal_mock.volume_target.get.assert_called_once_with( - *args, fields=fields) - collist = ('uuid', 'volume_id') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_volume_target_uuid, - baremetal_fakes.baremetal_volume_target_volume_id, - ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_target_show_fields_multiple(self): - arglist = ['vvv-tttttt-vvvv', '--fields', 'uuid', 'volume_id', - '--fields', 'volume_type'] - verifylist = [('fields', [['uuid', 'volume_id'], ['volume_type']]), - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid)] - - fake_vt = copy.deepcopy(baremetal_fakes.VOLUME_TARGET) - fake_vt.pop('node_uuid') - fake_vt.pop('boot_index') - fake_vt.pop('extra') - fake_vt.pop('properties') - self.baremetal_mock.volume_target.get.return_value = ( - baremetal_fakes.FakeBaremetalResource( - None, - fake_vt, - loaded=True)) - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - args = ['vvv-tttttt-vvvv'] - fields = ['uuid', 'volume_id', 'volume_type'] - self.baremetal_mock.volume_target.get.assert_called_once_with( - *args, fields=fields) - collist = ('uuid', 'volume_id', 'volume_type') - self.assertEqual(collist, columns) - - datalist = ( - baremetal_fakes.baremetal_volume_target_uuid, - baremetal_fakes.baremetal_volume_target_volume_id, - baremetal_fakes.baremetal_volume_target_volume_type, - ) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_target_show_invalid_fields(self): - arglist = ['vvv-tttttt-vvvv', '--fields', 'uuid', 'invalid'] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - -class TestListBaremetalVolumeTarget(TestBaremetalVolumeTarget): - def setUp(self): - super(TestListBaremetalVolumeTarget, self).setUp() - - self.baremetal_mock.volume_target.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - copy.deepcopy(baremetal_fakes.VOLUME_TARGET), - loaded=True) - ] - self.cmd = ( - bm_vol_target.ListBaremetalVolumeTarget(self.app, None)) - - def test_baremetal_volume_target_list(self): - arglist = [] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None} - self.baremetal_mock.volume_target.list.assert_called_once_with( - **kwargs) - - collist = ( - "UUID", - "Node UUID", - "Driver Volume Type", - "Boot Index", - "Volume ID") - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_target_uuid, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_volume_target_volume_type, - baremetal_fakes.baremetal_volume_target_boot_index, - baremetal_fakes.baremetal_volume_target_volume_id),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_target_list_node(self): - arglist = ['--node', baremetal_fakes.baremetal_uuid] - verifylist = [('node', baremetal_fakes.baremetal_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'node': baremetal_fakes.baremetal_uuid, - 'marker': None, - 'limit': None} - self.baremetal_mock.volume_target.list.assert_called_once_with( - **kwargs) - - collist = ( - "UUID", - "Node UUID", - "Driver Volume Type", - "Boot Index", - "Volume ID") - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_target_uuid, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_volume_target_volume_type, - baremetal_fakes.baremetal_volume_target_boot_index, - baremetal_fakes.baremetal_volume_target_volume_id),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_target_list_long(self): - arglist = ['--long'] - verifylist = [('detail', True)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'detail': True, - 'marker': None, - 'limit': None, - } - self.baremetal_mock.volume_target.list.assert_called_with(**kwargs) - - collist = ('UUID', 'Node UUID', 'Driver Volume Type', 'Properties', - 'Boot Index', 'Extra', 'Volume ID', 'Created At', - 'Updated At') - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_target_uuid, - baremetal_fakes.baremetal_uuid, - baremetal_fakes.baremetal_volume_target_volume_type, - baremetal_fakes.baremetal_volume_target_properties, - baremetal_fakes.baremetal_volume_target_boot_index, - baremetal_fakes.baremetal_volume_target_extra, - baremetal_fakes.baremetal_volume_target_volume_id, - '', - ''),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_target_list_fields(self): - arglist = ['--fields', 'uuid', 'boot_index'] - verifylist = [('fields', [['uuid', 'boot_index']])] - - fake_vt = copy.deepcopy(baremetal_fakes.VOLUME_TARGET) - fake_vt.pop('volume_type') - fake_vt.pop('extra') - fake_vt.pop('properties') - fake_vt.pop('volume_id') - fake_vt.pop('node_uuid') - self.baremetal_mock.volume_target.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - fake_vt, - loaded=True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'detail': False, - 'marker': None, - 'limit': None, - 'fields': ('uuid', 'boot_index') - } - self.baremetal_mock.volume_target.list.assert_called_with(**kwargs) - - collist = ('UUID', 'Boot Index') - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_target_uuid, - baremetal_fakes.baremetal_volume_target_boot_index),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_target_list_fields_multiple(self): - arglist = ['--fields', 'uuid', 'boot_index', '--fields', 'extra'] - verifylist = [('fields', [['uuid', 'boot_index'], ['extra']])] - - fake_vt = copy.deepcopy(baremetal_fakes.VOLUME_TARGET) - fake_vt.pop('volume_type') - fake_vt.pop('properties') - fake_vt.pop('volume_id') - fake_vt.pop('node_uuid') - self.baremetal_mock.volume_target.list.return_value = [ - baremetal_fakes.FakeBaremetalResource( - None, - fake_vt, - loaded=True) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) - - kwargs = { - 'detail': False, - 'marker': None, - 'limit': None, - 'fields': ('uuid', 'boot_index', 'extra') - } - self.baremetal_mock.volume_target.list.assert_called_with(**kwargs) - - collist = ('UUID', 'Boot Index', 'Extra') - self.assertEqual(collist, columns) - - datalist = ((baremetal_fakes.baremetal_volume_target_uuid, - baremetal_fakes.baremetal_volume_target_boot_index, - baremetal_fakes.baremetal_volume_target_extra),) - self.assertEqual(datalist, tuple(data)) - - def test_baremetal_volume_target_list_invalid_fields(self): - arglist = ['--fields', 'uuid', 'invalid'] - verifylist = [('fields', [['uuid', 'invalid']])] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_target_list_marker(self): - arglist = ['--marker', baremetal_fakes.baremetal_volume_target_uuid] - verifylist = [ - ('marker', baremetal_fakes.baremetal_volume_target_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': baremetal_fakes.baremetal_volume_target_uuid, - 'limit': None} - self.baremetal_mock.volume_target.list.assert_called_once_with( - **kwargs) - - def test_baremetal_volume_target_list_limit(self): - arglist = ['--limit', '10'] - verifylist = [('limit', 10)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': 10} - self.baremetal_mock.volume_target.list.assert_called_once_with( - **kwargs) - - def test_baremetal_volume_target_list_sort(self): - arglist = ['--sort', 'boot_index'] - verifylist = [('sort', 'boot_index')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None} - self.baremetal_mock.volume_target.list.assert_called_once_with( - **kwargs) - - def test_baremetal_volume_target_list_sort_desc(self): - arglist = ['--sort', 'boot_index:desc'] - verifylist = [('sort', 'boot_index:desc')] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - kwargs = { - 'marker': None, - 'limit': None} - self.baremetal_mock.volume_target.list.assert_called_once_with( - **kwargs) - - def test_baremetal_volume_target_list_exclusive_options(self): - arglist = ['--fields', 'uuid', '--long'] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, []) - - def test_baremetal_volume_target_list_negative_limit(self): - arglist = ['--limit', '-1'] - verifylist = [('limit', -1)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - - -class TestDeleteBaremetalVolumeTarget(TestBaremetalVolumeTarget): - - def setUp(self): - super(TestDeleteBaremetalVolumeTarget, self).setUp() - - self.cmd = bm_vol_target.DeleteBaremetalVolumeTarget(self.app, None) - - def test_baremetal_volume_target_delete(self): - arglist = [baremetal_fakes.baremetal_volume_target_uuid] - verifylist = [('volume_targets', - [baremetal_fakes.baremetal_volume_target_uuid])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.baremetal_mock.volume_target.delete.assert_called_with( - baremetal_fakes.baremetal_volume_target_uuid) - - def test_baremetal_volume_target_delete_multiple(self): - fake_volume_target_uuid2 = 'vvv-tttttt-tttt' - arglist = [baremetal_fakes.baremetal_volume_target_uuid, - fake_volume_target_uuid2] - verifylist = [('volume_targets', - [baremetal_fakes.baremetal_volume_target_uuid, - fake_volume_target_uuid2])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.baremetal_mock.volume_target.delete.has_calls( - [mock.call(baremetal_fakes.baremetal_volume_target_uuid), - mock.call(fake_volume_target_uuid2)]) - self.assertEqual( - 2, self.baremetal_mock.volume_target.delete.call_count) - - def test_baremetal_volume_target_delete_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_target_delete_error(self): - arglist = [baremetal_fakes.baremetal_volume_target_uuid] - verifylist = [('volume_targets', - [baremetal_fakes.baremetal_volume_target_uuid])] - - self.baremetal_mock.volume_target.delete.side_effect = ( - exc.NotFound()) - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises(exc.ClientException, - self.cmd.take_action, - parsed_args) - self.baremetal_mock.volume_target.delete.assert_called_with( - baremetal_fakes.baremetal_volume_target_uuid) - - def test_baremetal_volume_target_delete_multiple_error(self): - fake_volume_target_uuid2 = 'vvv-tttttt-tttt' - arglist = [baremetal_fakes.baremetal_volume_target_uuid, - fake_volume_target_uuid2] - verifylist = [('volume_targets', - [baremetal_fakes.baremetal_volume_target_uuid, - fake_volume_target_uuid2])] - - self.baremetal_mock.volume_target.delete.side_effect = [ - None, exc.NotFound()] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises(exc.ClientException, - self.cmd.take_action, - parsed_args) - - self.baremetal_mock.volume_target.delete.has_calls( - [mock.call(baremetal_fakes.baremetal_volume_target_uuid), - mock.call(fake_volume_target_uuid2)]) - self.assertEqual( - 2, self.baremetal_mock.volume_target.delete.call_count) - - -class TestSetBaremetalVolumeTarget(TestBaremetalVolumeTarget): - def setUp(self): - super(TestSetBaremetalVolumeTarget, self).setUp() - - self.cmd = ( - bm_vol_target.SetBaremetalVolumeTarget(self.app, None)) - - def test_baremetal_volume_target_set_node_uuid(self): - new_node_uuid = 'xxx-xxxxxx-zzzz' - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--node', new_node_uuid] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('node_uuid', new_node_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/node_uuid', 'value': new_node_uuid, 'op': 'add'}]) - - def test_baremetal_volume_target_set_volume_type(self): - new_type = 'fibre_channel' - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--type', new_type] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('volume_type', new_type)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/volume_type', 'value': new_type, 'op': 'add'}]) - - def test_baremetal_volume_target_set_boot_index(self): - new_boot_idx = '3' - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--boot-index', new_boot_idx] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('boot_index', int(new_boot_idx))] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/boot_index', 'value': int(new_boot_idx), 'op': 'add'}]) - - def test_baremetal_volume_target_set_negative_boot_index(self): - new_boot_idx = '-3' - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--boot-index', new_boot_idx] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('boot_index', int(new_boot_idx))] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) - - def test_baremetal_volume_target_set_invalid_boot_index(self): - new_boot_idx = 'string' - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--boot-index', new_boot_idx] - verifylist = None - - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_target_set_volume_id(self): - new_volume_id = 'new-volume-id' - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--volume-id', new_volume_id] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('volume_id', new_volume_id)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/volume_id', 'value': new_volume_id, 'op': 'add'}]) - - def test_baremetal_volume_target_set_volume_type_and_volume_id(self): - new_volume_type = 'fibre_channel' - new_volume_id = 'new-volume-id' - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--type', new_volume_type, - '--volume-id', new_volume_id] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('volume_type', new_volume_type), - ('volume_id', new_volume_id)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/volume_type', 'value': new_volume_type, 'op': 'add'}, - {'path': '/volume_id', 'value': new_volume_id, 'op': 'add'}]) - - def test_baremetal_volume_target_set_extra(self): - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--extra', 'foo=bar'] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('extra', ['foo=bar'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}]) - - def test_baremetal_volume_target_set_multiple_extras(self): - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--extra', 'key1=val1', '--extra', 'key2=val2'] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('extra', ['key1=val1', 'key2=val2'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/extra/key1', 'value': 'val1', 'op': 'add'}, - {'path': '/extra/key2', 'value': 'val2', 'op': 'add'}]) - - def test_baremetal_volume_target_set_property(self): - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--property', 'foo=bar'] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('properties', ['foo=bar'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/properties/foo', 'value': 'bar', 'op': 'add'}]) - - def test_baremetal_volume_target_set_multiple_properties(self): - arglist = [ - baremetal_fakes.baremetal_volume_target_uuid, - '--property', 'key1=val1', '--property', 'key2=val2'] - verifylist = [ - ('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('properties', ['key1=val1', 'key2=val2'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/properties/key1', 'value': 'val1', 'op': 'add'}, - {'path': '/properties/key2', 'value': 'val2', 'op': 'add'}]) - - def test_baremetal_volume_target_set_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_target_set_no_property(self): - arglist = [baremetal_fakes.baremetal_volume_target_uuid] - verifylist = [('volume_target', - baremetal_fakes.baremetal_volume_target_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_not_called() - - -class TestUnsetBaremetalVolumeTarget(TestBaremetalVolumeTarget): - def setUp(self): - super(TestUnsetBaremetalVolumeTarget, self).setUp() - - self.cmd = bm_vol_target.UnsetBaremetalVolumeTarget(self.app, None) - - def test_baremetal_volume_target_unset_extra(self): - arglist = [baremetal_fakes.baremetal_volume_target_uuid, - '--extra', 'key1'] - verifylist = [('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('extra', ['key1'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/extra/key1', 'op': 'remove'}]) - - def test_baremetal_volume_target_unset_multiple_extras(self): - arglist = [baremetal_fakes.baremetal_volume_target_uuid, - '--extra', 'key1', '--extra', 'key2'] - verifylist = [('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('extra', ['key1', 'key2'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/extra/key1', 'op': 'remove'}, - {'path': '/extra/key2', 'op': 'remove'}]) - - def test_baremetal_volume_target_unset_property(self): - arglist = [baremetal_fakes.baremetal_volume_target_uuid, - '--property', 'key11'] - verifylist = [('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('properties', ['key11'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/properties/key11', 'op': 'remove'}]) - - def test_baremetal_volume_target_unset_multiple_properties(self): - arglist = [baremetal_fakes.baremetal_volume_target_uuid, - '--property', 'key11', '--property', 'key22'] - verifylist = [('volume_target', - baremetal_fakes.baremetal_volume_target_uuid), - ('properties', ['key11', 'key22'])] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_called_once_with( - baremetal_fakes.baremetal_volume_target_uuid, - [{'path': '/properties/key11', 'op': 'remove'}, - {'path': '/properties/key22', 'op': 'remove'}]) - - def test_baremetal_volume_target_unset_no_options(self): - arglist = [] - verifylist = [] - self.assertRaises(osctestutils.ParserException, - self.check_parser, - self.cmd, arglist, verifylist) - - def test_baremetal_volume_target_unset_no_property(self): - arglist = [baremetal_fakes.baremetal_volume_target_uuid] - verifylist = [('volume_target', - baremetal_fakes.baremetal_volume_target_uuid)] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.baremetal_mock.volume_target.update.assert_not_called() diff --git a/ironicclient/tests/unit/test_client.py b/ironicclient/tests/unit/test_client.py deleted file mode 100644 index be60aed..0000000 --- a/ironicclient/tests/unit/test_client.py +++ /dev/null @@ -1,373 +0,0 @@ -# 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 mock - -from keystoneauth1 import loading as kaloading - -from ironicclient import client as iroclient -from ironicclient.common import filecache -from ironicclient.common import http -from ironicclient import exc -from ironicclient.tests.unit import utils -from ironicclient.v1 import client as v1 - - -class ClientTest(utils.BaseTestCase): - - def test_get_client_with_auth_token_ironic_url(self): - kwargs = { - 'ironic_url': 'http://ironic.example.org:6385/', - 'os_auth_token': 'USER_AUTH_TOKEN', - } - client = iroclient.get_client('1', **kwargs) - - self.assertEqual('USER_AUTH_TOKEN', client.http_client.auth_token) - self.assertEqual('http://ironic.example.org:6385/', - client.http_client.endpoint) - - @mock.patch.object(filecache, 'retrieve_data', autospec=True) - @mock.patch.object(kaloading.session, 'Session', autospec=True) - @mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) - def _test_get_client(self, mock_ks_loader, mock_ks_session, - mock_retrieve_data, version=None, - auth='password', **kwargs): - session = mock_ks_session.return_value.load_from_options.return_value - session.get_endpoint.return_value = 'http://localhost:6385/v1/f14b4123' - mock_ks_loader.return_value.load_from_options.return_value = 'auth' - mock_retrieve_data.return_value = version - - client = iroclient.get_client('1', **kwargs) - - mock_ks_loader.assert_called_once_with(auth) - mock_ks_session.return_value.load_from_options.assert_called_once_with( - auth='auth', timeout=kwargs.get('timeout'), - insecure=kwargs.get('insecure'), cert=kwargs.get('cert'), - cacert=kwargs.get('cacert'), key=kwargs.get('key')) - session.get_endpoint.assert_called_once_with( - service_type=kwargs.get('os_service_type') or 'baremetal', - interface=kwargs.get('os_endpoint_type') or 'publicURL', - region_name=kwargs.get('os_region_name')) - if 'os_ironic_api_version' in kwargs: - self.assertEqual(0, mock_retrieve_data.call_count) - else: - mock_retrieve_data.assert_called_once_with( - host='localhost', - port='6385') - self.assertEqual(version or v1.DEFAULT_VER, - client.http_client.os_ironic_api_version) - - def test_get_client_no_auth_token(self): - kwargs = { - 'os_project_name': 'PROJECT_NAME', - 'os_username': 'USERNAME', - 'os_password': 'PASSWORD', - 'os_auth_url': 'http://localhost:35357/v2.0', - 'os_auth_token': '', - } - self._test_get_client(**kwargs) - - def test_get_client_service_and_endpoint_type_defaults(self): - kwargs = { - 'os_project_name': 'PROJECT_NAME', - 'os_username': 'USERNAME', - 'os_password': 'PASSWORD', - 'os_auth_url': 'http://localhost:35357/v2.0', - 'os_auth_token': '', - 'os_service_type': '', - 'os_endpoint_type': '' - } - self._test_get_client(**kwargs) - - def test_get_client_with_region_no_auth_token(self): - kwargs = { - 'os_project_name': 'PROJECT_NAME', - 'os_username': 'USERNAME', - 'os_password': 'PASSWORD', - 'os_region_name': 'REGIONONE', - 'os_auth_url': 'http://localhost:35357/v2.0', - 'os_auth_token': '', - } - self._test_get_client(**kwargs) - - def test_get_client_no_url(self): - kwargs = { - 'os_project_name': 'PROJECT_NAME', - 'os_username': 'USERNAME', - 'os_password': 'PASSWORD', - 'os_auth_url': '', - } - self.assertRaises(exc.AmbiguousAuthSystem, iroclient.get_client, - '1', **kwargs) - # test the alias as well to ensure backwards compatibility - self.assertRaises(exc.AmbigiousAuthSystem, iroclient.get_client, - '1', **kwargs) - - def test_get_client_incorrect_auth_params(self): - kwargs = { - 'os_project_name': 'PROJECT_NAME', - 'os_username': 'USERNAME', - 'os_auth_url': 'http://localhost:35357/v2.0', - } - self.assertRaises(exc.AmbiguousAuthSystem, iroclient.get_client, - '1', **kwargs) - - def test_get_client_with_api_version_latest(self): - kwargs = { - 'os_project_name': 'PROJECT_NAME', - 'os_username': 'USERNAME', - 'os_password': 'PASSWORD', - 'os_auth_url': 'http://localhost:35357/v2.0', - 'os_auth_token': '', - 'os_ironic_api_version': "latest", - } - self._test_get_client(**kwargs) - - def test_get_client_with_api_version_numeric(self): - kwargs = { - 'os_project_name': 'PROJECT_NAME', - 'os_username': 'USERNAME', - 'os_password': 'PASSWORD', - 'os_auth_url': 'http://localhost:35357/v2.0', - 'os_auth_token': '', - 'os_ironic_api_version': "1.4", - } - self._test_get_client(**kwargs) - - def test_get_client_default_version_set_cached(self): - version = '1.3' - # Make sure we don't coincidentally succeed - self.assertNotEqual(v1.DEFAULT_VER, version) - kwargs = { - 'os_project_name': 'PROJECT_NAME', - 'os_username': 'USERNAME', - 'os_password': 'PASSWORD', - 'os_auth_url': 'http://localhost:35357/v2.0', - 'os_auth_token': '', - } - self._test_get_client(version=version, **kwargs) - - def test_get_client_with_auth_token(self): - kwargs = { - 'os_auth_url': 'http://localhost:35357/v2.0', - 'os_auth_token': 'USER_AUTH_TOKEN', - } - self._test_get_client(auth='token', **kwargs) - - def test_get_client_with_region_name_auth_token(self): - kwargs = { - 'os_auth_url': 'http://localhost:35357/v2.0', - 'os_region_name': 'REGIONONE', - 'os_auth_token': 'USER_AUTH_TOKEN', - } - self._test_get_client(auth='token', **kwargs) - - def test_get_client_only_session_passed(self): - session = mock.Mock() - session.get_endpoint.return_value = 'http://localhost:35357/v2.0' - kwargs = { - 'session': session, - } - iroclient.get_client('1', **kwargs) - session.get_endpoint.assert_called_once_with(service_type='baremetal', - interface='publicURL', - region_name=None) - - def test_get_client_incorrect_session_passed(self): - session = mock.Mock() - session.get_endpoint.side_effect = Exception('boo') - kwargs = { - 'session': session, - } - self.assertRaises(exc.AmbiguousAuthSystem, iroclient.get_client, - '1', **kwargs) - - @mock.patch.object(kaloading.session, 'Session', autospec=True) - @mock.patch.object(kaloading, 'get_plugin_loader', autospec=True) - def _test_loader_arguments_passed_correctly( - self, mock_ks_loader, mock_ks_session, - passed_kwargs, expected_kwargs): - session = mock_ks_session.return_value.load_from_options.return_value - session.get_endpoint.return_value = 'http://localhost:6385/v1/f14b4123' - mock_ks_loader.return_value.load_from_options.return_value = 'auth' - - iroclient.get_client('1', **passed_kwargs) - - mock_ks_loader.return_value.load_from_options.assert_called_once_with( - **expected_kwargs) - mock_ks_session.return_value.load_from_options.assert_called_once_with( - auth='auth', timeout=passed_kwargs.get('timeout'), - insecure=passed_kwargs.get('insecure'), - cert=passed_kwargs.get('cert'), - cacert=passed_kwargs.get('cacert'), key=passed_kwargs.get('key')) - session.get_endpoint.assert_called_once_with( - service_type=passed_kwargs.get('os_service_type') or 'baremetal', - interface=passed_kwargs.get('os_endpoint_type') or 'publicURL', - region_name=passed_kwargs.get('os_region_name')) - - def test_loader_arguments_token(self): - passed_kwargs = { - 'os_auth_url': 'http://localhost:35357/v3', - 'os_region_name': 'REGIONONE', - 'os_auth_token': 'USER_AUTH_TOKEN', - } - expected_kwargs = { - 'auth_url': 'http://localhost:35357/v3', - 'project_id': None, - 'project_name': None, - 'user_domain_id': None, - 'user_domain_name': None, - 'project_domain_id': None, - 'project_domain_name': None, - 'token': 'USER_AUTH_TOKEN' - } - self._test_loader_arguments_passed_correctly( - passed_kwargs=passed_kwargs, expected_kwargs=expected_kwargs) - - def test_loader_arguments_password_tenant_name(self): - passed_kwargs = { - 'os_auth_url': 'http://localhost:35357/v3', - 'os_region_name': 'REGIONONE', - 'os_project_name': 'PROJECT', - 'os_username': 'user', - 'os_password': '1234', - 'os_project_domain_id': 'DEFAULT', - 'os_user_domain_id': 'DEFAULT' - } - expected_kwargs = { - 'auth_url': 'http://localhost:35357/v3', - 'project_id': None, - 'project_name': 'PROJECT', - 'user_domain_id': 'DEFAULT', - 'user_domain_name': None, - 'project_domain_id': 'DEFAULT', - 'project_domain_name': None, - 'username': 'user', - 'password': '1234' - } - self._test_loader_arguments_passed_correctly( - passed_kwargs=passed_kwargs, expected_kwargs=expected_kwargs) - - def test_loader_arguments_password_project_id(self): - passed_kwargs = { - 'os_auth_url': 'http://localhost:35357/v3', - 'os_region_name': 'REGIONONE', - 'os_project_id': '1000', - 'os_username': 'user', - 'os_password': '1234', - 'os_project_domain_name': 'domain1', - 'os_user_domain_name': 'domain1' - } - expected_kwargs = { - 'auth_url': 'http://localhost:35357/v3', - 'project_id': '1000', - 'project_name': None, - 'user_domain_id': None, - 'user_domain_name': 'domain1', - 'project_domain_id': None, - 'project_domain_name': 'domain1', - 'username': 'user', - 'password': '1234' - } - self._test_loader_arguments_passed_correctly( - passed_kwargs=passed_kwargs, expected_kwargs=expected_kwargs) - - @mock.patch.object(iroclient, 'Client', autospec=True) - @mock.patch.object(kaloading.session, 'Session', autospec=True) - def test_correct_arguments_passed_to_client_constructor_noauth_mode( - self, mock_ks_session, mock_client): - kwargs = { - 'ironic_url': 'http://ironic.example.org:6385/', - 'os_auth_token': 'USER_AUTH_TOKEN', - 'os_ironic_api_version': 'latest', - 'insecure': True, - 'max_retries': 10, - 'retry_interval': 10, - 'os_cacert': 'data' - } - iroclient.get_client('1', **kwargs) - mock_client.assert_called_once_with( - '1', 'http://ironic.example.org:6385/', - **{ - 'os_ironic_api_version': 'latest', - 'max_retries': 10, - 'retry_interval': 10, - 'token': 'USER_AUTH_TOKEN', - 'insecure': True, - 'ca_file': 'data', - 'cert_file': None, - 'key_file': None, - 'timeout': None, - 'session': None - } - ) - self.assertFalse(mock_ks_session.called) - - @mock.patch.object(iroclient, 'Client', autospec=True) - @mock.patch.object(kaloading.session, 'Session', autospec=True) - def test_correct_arguments_passed_to_client_constructor_session_created( - self, mock_ks_session, mock_client): - session = mock_ks_session.return_value.load_from_options.return_value - kwargs = { - 'os_auth_url': 'http://localhost:35357/v3', - 'os_region_name': 'REGIONONE', - 'os_project_id': '1000', - 'os_username': 'user', - 'os_password': '1234', - 'os_project_domain_name': 'domain1', - 'os_user_domain_name': 'domain1' - } - iroclient.get_client('1', **kwargs) - mock_client.assert_called_once_with( - '1', session.get_endpoint.return_value, - **{ - 'os_ironic_api_version': None, - 'max_retries': None, - 'retry_interval': None, - 'session': session, - } - ) - - @mock.patch.object(iroclient, 'Client', autospec=True) - @mock.patch.object(kaloading.session, 'Session', autospec=True) - def test_correct_arguments_passed_to_client_constructor_session_passed( - self, mock_ks_session, mock_client): - session = mock.Mock() - kwargs = { - 'session': session, - } - iroclient.get_client('1', **kwargs) - mock_client.assert_called_once_with( - '1', session.get_endpoint.return_value, - **{ - 'os_ironic_api_version': None, - 'max_retries': None, - 'retry_interval': None, - 'session': session, - } - ) - self.assertFalse(mock_ks_session.called) - - def test_safe_header_with_auth_token(self): - (name, value) = ('X-Auth-Token', u'3b640e2e64d946ac8f55615aff221dc1') - expected_header = (u'X-Auth-Token', - '{SHA1}6de9fb3b0b89099030a54abfeb468e7b1b1f0f2b') - client = http.HTTPClient('http://localhost/') - header_redact = client._process_header(name, value) - self.assertEqual(expected_header, header_redact) - - def test_safe_header_with_no_auth_token(self): - name, value = ('Accept', 'application/json') - header = ('Accept', 'application/json') - client = http.HTTPClient('http://localhost/') - header_redact = client._process_header(name, value) - self.assertEqual(header, header_redact) diff --git a/ironicclient/tests/unit/test_exc.py b/ironicclient/tests/unit/test_exc.py deleted file mode 100644 index d7c8382..0000000 --- a/ironicclient/tests/unit/test_exc.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2015 Red Hat, 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 mock -from six.moves import http_client - -from ironicclient.common.apiclient import exceptions -from ironicclient import exc -from ironicclient.tests.unit import utils as test_utils - - -@mock.patch.object(exceptions, 'from_response', autospec=True) -class ExcTest(test_utils.BaseTestCase): - - def setUp(self): - super(ExcTest, self).setUp() - self.message = 'SpongeBob SquarePants' - self.traceback = 'Foo Traceback' - self.method = 'call_spongebob' - self.url = 'http://foo.bar' - self.expected_json = {'error': {'message': self.message, - 'details': self.traceback}} - - def test_from_response(self, mock_apiclient): - fake_response = mock.Mock(status_code=http_client.BAD_REQUEST) - exc.from_response(fake_response, message=self.message, - traceback=self.traceback, method=self.method, - url=self.url) - self.assertEqual(http_client.BAD_REQUEST, fake_response.status_code) - self.assertEqual(self.expected_json, fake_response.json()) - mock_apiclient.assert_called_once_with( - fake_response, method=self.method, url=self.url) - - def test_from_response_status(self, mock_apiclient): - fake_response = mock.Mock(status=http_client.BAD_REQUEST) - fake_response.getheader.return_value = 'fake-header' - delattr(fake_response, 'status_code') - - exc.from_response(fake_response, message=self.message, - traceback=self.traceback, method=self.method, - url=self.url) - expected_header = {'Content-Type': 'fake-header'} - self.assertEqual(expected_header, fake_response.headers) - self.assertEqual(http_client.BAD_REQUEST, fake_response.status_code) - self.assertEqual(self.expected_json, fake_response.json()) - mock_apiclient.assert_called_once_with( - fake_response, method=self.method, url=self.url) diff --git a/ironicclient/tests/unit/test_import.py b/ironicclient/tests/unit/test_import.py deleted file mode 100644 index 5e1881e..0000000 --- a/ironicclient/tests/unit/test_import.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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 ironicclient.tests.unit import utils - -module_str = 'ironicclient' - - -class ImportTest(utils.BaseTestCase): - - def check_exported_symbols(self, exported_symbols): - self.assertIn('client', exported_symbols) - self.assertIn('exc', exported_symbols) - self.assertIn('exceptions', exported_symbols) - - def test_import_objects(self): - module = __import__(module_str) - exported_symbols = dir(module) - self.check_exported_symbols(exported_symbols) - - def test_default_import(self): - default_imports = __import__(module_str, globals(), locals(), ['*']) - exported_symbols = dir(default_imports) - self.check_exported_symbols(exported_symbols) - - def test_import__all__(self): - module = __import__(module_str) - self.check_exported_symbols(module.__all__) diff --git a/ironicclient/tests/unit/test_shell.py b/ironicclient/tests/unit/test_shell.py deleted file mode 100644 index 77a2f19..0000000 --- a/ironicclient/tests/unit/test_shell.py +++ /dev/null @@ -1,398 +0,0 @@ -# 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 re -import sys - -import fixtures -from keystoneauth1 import exceptions as keystone_exc -from keystoneauth1 import fixture as ks_fixture -import mock -from oslo_utils import uuidutils -import requests_mock -import six -import testtools -from testtools import matchers - -from ironicclient import client -from ironicclient.common.apiclient import exceptions -from ironicclient.common import http -from ironicclient import exc -from ironicclient import shell as ironic_shell -from ironicclient.tests.unit import utils - -BASE_URL = 'http://no.where:5000' -V2_URL = BASE_URL + '/v2.0' -V3_URL = BASE_URL + '/v3' - -FAKE_ENV = {'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_PROJECT_NAME': 'project_name', - 'OS_AUTH_URL': V2_URL} - -FAKE_ENV_KEYSTONE_V2 = { - 'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_PROJECT_NAME': 'project_name', - 'OS_AUTH_URL': V2_URL -} - -FAKE_ENV_KEYSTONE_V3 = { - 'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_PROJECT_NAME': 'project_name', - 'OS_AUTH_URL': V3_URL, - 'OS_USER_DOMAIN_ID': 'default', - 'OS_PROJECT_DOMAIN_ID': 'default', -} - -FAKE_ENV_KEYSTONE_V2_TOKEN = { - 'OS_AUTH_TOKEN': 'admin_token', - 'OS_PROJECT_NAME': 'project_name', - 'OS_AUTH_URL': V2_URL -} - - -class ShellTest(utils.BaseTestCase): - re_options = re.DOTALL | re.MULTILINE - - # Patch os.environ to avoid required auth info. - def make_env(self, exclude=None, environ_dict=FAKE_ENV): - env = dict((k, v) for k, v in environ_dict.items() if k != exclude) - self.useFixture(fixtures.MonkeyPatch('os.environ', env)) - - def setUp(self): - super(ShellTest, self).setUp() - - def shell(self, argstr): - with mock.patch.object(sys, 'stdout', six.StringIO()): - with mock.patch.object(sys, 'stderr', six.StringIO()): - try: - _shell = ironic_shell.IronicShell() - _shell.main(argstr.split()) - except SystemExit: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.assertEqual(0, exc_value.code) - finally: - out = sys.stdout.getvalue() - err = sys.stderr.getvalue() - return out, err - - def test_help_unknown_command(self): - self.assertRaises(exc.CommandError, self.shell, 'help foofoo') - - def test_help(self): - required = [ - '.*?^usage: ironic', - '.*?^ +bash-completion', - '.*?^See "ironic help COMMAND" ' - 'for help on a specific command', - ] - for argstr in ['--help', 'help']: - help_text = self.shell(argstr)[0] - for r in required: - self.assertThat(help_text, - matchers.MatchesRegex(r, - self.re_options)) - - def test_help_on_subcommand(self): - required = [ - ".*?^usage: ironic chassis-show", - ".*?^Show detailed information about a chassis", - ] - argstrings = [ - 'help chassis-show', - ] - for argstr in argstrings: - help_text = self.shell(argstr)[0] - for r in required: - self.assertThat(help_text, - matchers.MatchesRegex(r, self.re_options)) - - def test_required_args_on_node_create_help(self): - required = [ - ".*?^usage: ironic node-create", - ".*?^Register a new node with the Ironic service", - ".*?^Required arguments:", - ] - argstrings = [ - 'help node-create', - ] - for argstr in argstrings: - help_text = self.shell(argstr)[0] - for r in required: - self.assertThat(help_text, - matchers.MatchesRegex(r, self.re_options)) - - def test_required_args_on_port_create_help(self): - required = [ - ".*?^usage: ironic port-create", - ".*?^Create a new port", - ".*?^Required arguments:", - ] - argstrings = [ - 'help port-create', - ] - for argstr in argstrings: - help_text = self.shell(argstr)[0] - for r in required: - self.assertThat(help_text, - matchers.MatchesRegex(r, self.re_options)) - - def test_auth_param(self): - self.make_env(exclude='OS_USERNAME') - self.test_help() - - @mock.patch.object(client, 'get_client', autospec=True, - side_effect=keystone_exc.ConnectFailure) - @mock.patch('sys.stdin', side_effect=mock.MagicMock, autospec=True) - @mock.patch('getpass.getpass', return_value='password', autospec=True) - def test_password_prompted(self, mock_getpass, mock_stdin, mock_client): - self.make_env(exclude='OS_PASSWORD') - # We will get a ConnectFailure because there is no keystone. - self.assertRaises(keystone_exc.ConnectFailure, - self.shell, 'node-list') - expected_kwargs = { - 'ironic_url': '', 'os_auth_url': FAKE_ENV['OS_AUTH_URL'], - 'os_tenant_id': '', 'os_tenant_name': '', - 'os_username': FAKE_ENV['OS_USERNAME'], 'os_user_domain_id': '', - 'os_user_domain_name': '', 'os_password': FAKE_ENV['OS_PASSWORD'], - 'os_auth_token': '', 'os_project_id': '', - 'os_project_name': FAKE_ENV['OS_PROJECT_NAME'], - 'os_project_domain_id': '', - 'os_project_domain_name': '', 'os_region_name': '', - 'os_service_type': '', 'os_endpoint_type': '', 'os_cacert': None, - 'os_cert': None, 'os_key': None, - 'max_retries': http.DEFAULT_MAX_RETRIES, - 'retry_interval': http.DEFAULT_RETRY_INTERVAL, - 'os_ironic_api_version': None, 'timeout': 600, 'insecure': False - } - mock_client.assert_called_once_with(1, **expected_kwargs) - # Make sure we are actually prompted. - mock_getpass.assert_called_with('OpenStack Password: ') - - @mock.patch.object(client, 'get_client', autospec=True, - side_effect=keystone_exc.ConnectFailure) - @mock.patch('getpass.getpass', return_value='password', autospec=True) - def test_token_auth(self, mock_getpass, mock_client): - self.make_env(environ_dict=FAKE_ENV_KEYSTONE_V2_TOKEN) - # We will get a ConnectFailure because there is no keystone. - self.assertRaises(keystone_exc.ConnectFailure, - self.shell, 'node-list') - expected_kwargs = { - 'ironic_url': '', - 'os_auth_url': FAKE_ENV_KEYSTONE_V2_TOKEN['OS_AUTH_URL'], - 'os_tenant_id': '', - 'os_tenant_name': '', - 'os_username': '', 'os_user_domain_id': '', - 'os_user_domain_name': '', 'os_password': '', - 'os_auth_token': FAKE_ENV_KEYSTONE_V2_TOKEN['OS_AUTH_TOKEN'], - 'os_project_id': '', - 'os_project_name': FAKE_ENV_KEYSTONE_V2_TOKEN['OS_PROJECT_NAME'], - 'os_project_domain_id': '', 'os_project_domain_name': '', - 'os_region_name': '', 'os_service_type': '', - 'os_endpoint_type': '', 'os_cacert': None, 'os_cert': None, - 'os_key': None, 'max_retries': http.DEFAULT_MAX_RETRIES, - 'retry_interval': http.DEFAULT_RETRY_INTERVAL, - 'os_ironic_api_version': None, 'timeout': 600, 'insecure': False - } - mock_client.assert_called_once_with(1, **expected_kwargs) - self.assertFalse(mock_getpass.called) - - @mock.patch('sys.stdin', side_effect=mock.MagicMock, autospec=True) - @mock.patch('getpass.getpass', side_effect=EOFError, autospec=True) - def test_password_prompted_ctrlD(self, mock_getpass, mock_stdin): - self.make_env(exclude='OS_PASSWORD') - # We should get Command Error because we mock Ctl-D. - self.assertRaises(exc.CommandError, - self.shell, 'node-list') - # Make sure we are actually prompted. - mock_getpass.assert_called_with('OpenStack Password: ') - - @mock.patch('sys.stdin', autospec=True) - def test_no_password_no_tty(self, mock_stdin): - # delete the isatty attribute so that we do not get - # prompted when manually running the tests - del mock_stdin.isatty - required = ('You must provide a password' - ' via either --os-password, env[OS_PASSWORD],' - ' or prompted response',) - self.make_env(exclude='OS_PASSWORD') - try: - self.shell('node-list') - except exc.CommandError as message: - self.assertEqual(required, message.args) - else: - self.fail('CommandError not raised') - - def test_bash_completion(self): - stdout = self.shell('bash-completion')[0] - # just check we have some output - required = [ - '.*--driver_info', - '.*--chassis_uuid', - '.*help', - '.*node-create', - '.*chassis-create'] - for r in required: - self.assertThat(stdout, - matchers.MatchesRegex(r, self.re_options)) - - def test_ironic_api_version(self): - err = self.shell('--ironic-api-version 1.2 help')[1] - self.assertFalse(err) - - err = self.shell('--ironic-api-version latest help')[1] - self.assertFalse(err) - - self.assertRaises(exc.CommandError, - self.shell, '--ironic-api-version 1.2.1 help') - - def test_invalid_ironic_api_version(self): - self.assertRaises(exceptions.UnsupportedVersion, - self.shell, '--ironic-api-version 0.8 help') - - def test_warning_on_no_version(self): - err = self.shell('help')[1] - self.assertIn('You are using the default API version', err) - - -class TestCase(testtools.TestCase): - - def set_fake_env(self, fake_env): - client_env = ('OS_USERNAME', 'OS_PASSWORD', 'OS_PROJECT_ID', - 'OS_PROJECT_NAME', 'OS_AUTH_URL', 'OS_REGION_NAME', - 'OS_AUTH_TOKEN', 'OS_NO_CLIENT_AUTH', 'OS_SERVICE_TYPE', - 'OS_ENDPOINT_TYPE', 'OS_CACERT', 'OS_CERT', 'OS_KEY') - - for key in client_env: - self.useFixture( - fixtures.EnvironmentVariable(key, fake_env.get(key))) - - # required for testing with Python 2.6 - def assertRegexpMatches(self, text, expected_regexp, msg=None): - """Fail the test unless the text matches the regular expression.""" - if isinstance(expected_regexp, six.string_types): - expected_regexp = re.compile(expected_regexp) - if not expected_regexp.search(text): - msg = msg or "Regexp didn't match" - msg = '%s: %r not found in %r' % ( - msg, expected_regexp.pattern, text) - raise self.failureException(msg) - - def register_keystone_v2_token_fixture(self, request_mocker): - v2_token = ks_fixture.V2Token() - service = v2_token.add_service('baremetal') - service.add_endpoint('http://ironic.example.com', region='RegionOne') - request_mocker.post('%s/tokens' % V2_URL, - json=v2_token) - - def register_keystone_v3_token_fixture(self, request_mocker): - v3_token = ks_fixture.V3Token() - service = v3_token.add_service('baremetal') - service.add_standard_endpoints(public='http://ironic.example.com') - request_mocker.post( - '%s/auth/tokens' % V3_URL, - json=v3_token, - headers={'X-Subject-Token': uuidutils.generate_uuid()}) - - def register_keystone_auth_fixture(self, request_mocker): - self.register_keystone_v2_token_fixture(request_mocker) - self.register_keystone_v3_token_fixture(request_mocker) - - request_mocker.get(V2_URL, json=ks_fixture.V2Discovery(V2_URL)) - request_mocker.get(V3_URL, json=ks_fixture.V3Discovery(V3_URL)) - request_mocker.get(BASE_URL, json=ks_fixture.DiscoveryList(BASE_URL)) - - -class ShellTestNoMox(TestCase): - def setUp(self): - super(ShellTestNoMox, self).setUp() - self.set_fake_env(FAKE_ENV_KEYSTONE_V2) - - def shell(self, argstr): - orig = sys.stdout - try: - sys.stdout = six.StringIO() - _shell = ironic_shell.IronicShell() - _shell.main(argstr.split()) - self.subcommands = _shell.subcommands.keys() - except SystemExit: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.assertEqual(0, exc_value.code) - finally: - out = sys.stdout.getvalue() - sys.stdout.close() - sys.stdout = orig - - return out - - @requests_mock.mock() - def test_node_list(self, request_mocker): - self.register_keystone_auth_fixture(request_mocker) - resp_dict = {"nodes": [ - {"instance_uuid": "null", - "uuid": "351a82d6-9f04-4c36-b79a-a38b9e98ff71", - "links": [{"href": "http://ironic.example.com:6385/" - "v1/nodes/foo", - "rel": "self"}, - {"href": "http://ironic.example.com:6385/" - "nodes/foo", - "rel": "bookmark"}], - "maintenance": "false", - "provision_state": "null", - "power_state": "power off"}, - {"instance_uuid": "null", - "uuid": "66fbba13-29e8-4b8a-9e80-c655096a40d3", - "links": [{"href": "http://ironic.example.com:6385/" - "v1/nodes/foo2", - "rel": "self"}, - {"href": "http://ironic.example.com:6385/" - "nodes/foo2", - "rel": "bookmark"}], - "maintenance": "false", - "provision_state": "null", - "power_state": "power off"}]} - headers = {'Content-Type': 'application/json; charset=UTF-8'} - request_mocker.get('http://ironic.example.com/v1/nodes', - headers=headers, - json=resp_dict) - - event_list_text = self.shell('node-list') - - required = [ - '351a82d6-9f04-4c36-b79a-a38b9e98ff71', - '66fbba13-29e8-4b8a-9e80-c655096a40d3', - ] - - for r in required: - self.assertRegexpMatches(event_list_text, r) - - -class ShellTestNoMoxV3(ShellTestNoMox): - - def _set_fake_env(self): - self.set_fake_env(FAKE_ENV_KEYSTONE_V3) - - -class ShellParserTest(TestCase): - def test_deprecated_defaults(self): - cert_env = {} - cert_env['OS_CACERT'] = '/fake/cacert.pem' - cert_env['OS_CERT'] = '/fake/cert.pem' - cert_env['OS_KEY'] = '/fake/key.pem' - self.set_fake_env(cert_env) - parser = ironic_shell.IronicShell().get_base_parser() - options, _ = parser.parse_known_args([]) - self.assertEqual(cert_env['OS_CACERT'], options.os_cacert) - self.assertEqual(cert_env['OS_CERT'], options.os_cert) - self.assertEqual(cert_env['OS_KEY'], options.os_key) diff --git a/ironicclient/tests/unit/utils.py b/ironicclient/tests/unit/utils.py deleted file mode 100644 index 66526bf..0000000 --- a/ironicclient/tests/unit/utils.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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 copy -import os - -import fixtures -import mock -from oslo_utils import strutils -import requests -import six -import testtools - - -class BaseTestCase(testtools.TestCase): - def setUp(self): - super(BaseTestCase, self).setUp() - self.useFixture(fixtures.FakeLogger()) - - # If enabled, stdout and/or stderr is captured and will appear in - # test results if that test fails. - if strutils.bool_from_string(os.environ.get('OS_STDOUT_CAPTURE')): - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if strutils.bool_from_string(os.environ.get('OS_STDERR_CAPTURE')): - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - - -class FakeAPI(object): - def __init__(self, responses): - self.responses = responses - self.calls = [] - - def _request(self, method, url, headers=None, body=None): - call = (method, url, headers or {}, body) - self.calls.append(call) - return self.responses[url][method] - - def raw_request(self, *args, **kwargs): - response = self._request(*args, **kwargs) - body_iter = iter(six.StringIO(response[1])) - return FakeResponse(response[0]), body_iter - - def json_request(self, *args, **kwargs): - response = self._request(*args, **kwargs) - return FakeResponse(response[0]), response[1] - - -class FakeConnection(object): - def __init__(self, response=None): - self._response = response - self._last_request = None - - def request(self, method, conn_url, **kwargs): - self._last_request = (method, conn_url, kwargs) - - def setresponse(self, response): - self._response = response - - def getresponse(self): - return self._response - - def __repr__(self): - return ("FakeConnection(response=%s)" % (self._response)) - - -class FakeResponse(object): - def __init__(self, headers, body=None, version=None, status=None, - reason=None): - """Fake object to help testing. - - :param headers: dict representing HTTP response headers - :param body: file-like object - """ - self.headers = headers - self.body = body - self.raw = mock.Mock() - self.raw.version = version - self.status_code = status - self.reason = reason - - def getheaders(self): - return copy.deepcopy(self.headers).items() - - def getheader(self, key, default): - return self.headers.get(key, default) - - def read(self, amt): - return self.body.read(amt) - - def __repr__(self): - return ("FakeResponse(%s, body=%s, version=%s, status=%s, reason=%s)" % - (self.headers, self.body, self.version, self.status, - self.reason)) - - -def mockSessionResponse(headers, content=None, status_code=None, version=None): - raw = mock.Mock() - raw.version = version - response = mock.Mock(spec=requests.Response, - headers=headers, - content=content, - status_code=status_code, - raw=raw, - reason='', - encoding='UTF-8') - response.text = content - - return response - - -def mockSession(headers, content=None, status_code=None, version=None): - session = mock.Mock(spec=requests.Session, - verify=False, - cert=('test_cert', 'test_key')) - response = mockSessionResponse(headers, content, status_code, version) - session.request = mock.Mock(return_value=response) - - return session diff --git a/ironicclient/tests/unit/v1/__init__.py b/ironicclient/tests/unit/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/tests/unit/v1/test_chassis.py b/ironicclient/tests/unit/v1/test_chassis.py deleted file mode 100644 index d6f628d..0000000 --- a/ironicclient/tests/unit/v1/test_chassis.py +++ /dev/null @@ -1,463 +0,0 @@ -# Copyright 2013 Red Hat, 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 copy - -import testtools -from testtools.matchers import HasLength - -from ironicclient import exc -from ironicclient.tests.unit import utils -import ironicclient.v1.chassis - -CHASSIS = {'uuid': 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', - 'extra': {}, - 'description': 'data-center-1-chassis'} - -CHASSIS2 = {'uuid': 'eeeeeeee-dddd-cccc-bbbb-aaaaaaaaaaaa', - 'extra': {}, - 'description': 'data-center-1-chassis'} - - -NODE = {'uuid': '66666666-7777-8888-9999-000000000000', - 'chassis_uuid': 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', - 'provision_state': 'available', - 'driver': 'fake', - 'driver_info': {'user': 'foo', 'password': 'bar'}, - 'properties': {'num_cpu': 4}, - 'extra': {}} - -CREATE_CHASSIS = copy.deepcopy(CHASSIS) -del CREATE_CHASSIS['uuid'] - -CREATE_WITH_UUID = copy.deepcopy(CHASSIS) - -UPDATED_CHASSIS = copy.deepcopy(CHASSIS) -NEW_DESCR = 'new-description' -UPDATED_CHASSIS['description'] = NEW_DESCR - -fake_responses = { - '/v1/chassis': - { - 'GET': ( - {}, - {"chassis": [CHASSIS]}, - ), - 'POST': ( - {}, - CREATE_CHASSIS, - ), - }, - '/v1/chassis/detail': - { - 'GET': ( - {}, - {"chassis": [CHASSIS]}, - ), - }, - '/v1/chassis/?fields=uuid,extra': - { - 'GET': ( - {}, - {"chassis": [CHASSIS]}, - ), - }, - '/v1/chassis/%s' % CHASSIS['uuid']: - { - 'GET': ( - {}, - CHASSIS, - ), - 'DELETE': ( - {}, - None, - ), - 'PATCH': ( - {}, - UPDATED_CHASSIS, - ), - }, - '/v1/chassis/%s?fields=uuid,description' % CHASSIS['uuid']: - { - 'GET': ( - {}, - CHASSIS, - ), - }, - '/v1/chassis/%s/nodes' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ), - }, - '/v1/chassis/%s/nodes/detail' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ), - }, - '/v1/chassis/%s/nodes?fields=uuid,extra' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ), - }, - '/v1/chassis/%s/nodes?associated=True' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ) - }, - '/v1/chassis/%s/nodes?maintenance=False' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ) - }, - '/v1/chassis/%s/nodes?provision_state=available' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ) - }, -} - -fake_responses_pagination = { - '/v1/chassis': - { - 'GET': ( - {}, - {"chassis": [CHASSIS], - "next": "http://127.0.0.1:6385/v1/chassis/?limit=1"} - ), - }, - '/v1/chassis/?limit=1': - { - 'GET': ( - {}, - {"chassis": [CHASSIS2]} - ), - }, - '/v1/chassis/?marker=%s' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"chassis": [CHASSIS2]} - ), - }, - '/v1/chassis/%s/nodes?limit=1' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ), - }, - '/v1/chassis/%s/nodes?marker=%s' % (CHASSIS['uuid'], NODE['uuid']): - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ), - }, -} - -fake_responses_sorting = { - '/v1/chassis/?sort_key=updated_at': - { - 'GET': ( - {}, - {"chassis": [CHASSIS2]} - ), - }, - '/v1/chassis/?sort_dir=desc': - { - 'GET': ( - {}, - {"chassis": [CHASSIS2]} - ), - }, - '/v1/chassis/%s/nodes?sort_key=updated_at' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ), - }, - '/v1/chassis/%s/nodes?sort_dir=desc' % CHASSIS['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE]}, - ), - }, -} - - -class ChassisManagerTest(testtools.TestCase): - - def setUp(self): - super(ChassisManagerTest, self).setUp() - self.api = utils.FakeAPI(fake_responses) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - - def test_chassis_list(self): - chassis = self.mgr.list() - expect = [ - ('GET', '/v1/chassis', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(chassis)) - - def test_chassis_list_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - chassis = self.mgr.list(limit=1) - expect = [ - ('GET', '/v1/chassis/?limit=1', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(chassis, HasLength(1)) - - def test_chassis_list_marker(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - chassis = self.mgr.list(marker=CHASSIS['uuid']) - expect = [ - ('GET', '/v1/chassis/?marker=%s' % CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(chassis, HasLength(1)) - - def test_chassis_list_pagination_no_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - chassis = self.mgr.list(limit=0) - expect = [ - ('GET', '/v1/chassis', {}, None), - ('GET', '/v1/chassis/?limit=1', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(chassis, HasLength(2)) - - def test_chassis_list_sort_key(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - chassis = self.mgr.list(sort_key='updated_at') - expect = [ - ('GET', '/v1/chassis/?sort_key=updated_at', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(chassis, HasLength(1)) - - def test_chassis_list_sort_dir(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - chassis = self.mgr.list(sort_dir='desc') - expect = [ - ('GET', '/v1/chassis/?sort_dir=desc', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(chassis, HasLength(1)) - - def test_chassis_list_detail(self): - chassis = self.mgr.list(detail=True) - expect = [ - ('GET', '/v1/chassis/detail', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(chassis)) - - def test_chassis_list_fields(self): - nodes = self.mgr.list(fields=['uuid', 'extra']) - expect = [ - ('GET', '/v1/chassis/?fields=uuid,extra', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(nodes)) - - def test_chassis_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, self.mgr.list, - detail=True, fields=['uuid', 'extra']) - - def test_chassis_show(self): - chassis = self.mgr.get(CHASSIS['uuid']) - expect = [ - ('GET', '/v1/chassis/%s' % CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(CHASSIS['uuid'], chassis.uuid) - self.assertEqual(CHASSIS['description'], chassis.description) - - def test_chassis_show_fields(self): - chassis = self.mgr.get(CHASSIS['uuid'], fields=['uuid', 'description']) - expect = [ - ('GET', '/v1/chassis/%s?fields=uuid,description' % - CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(CHASSIS['uuid'], chassis.uuid) - self.assertEqual(CHASSIS['description'], chassis.description) - - def test_create(self): - chassis = self.mgr.create(**CREATE_CHASSIS) - expect = [ - ('POST', '/v1/chassis', {}, CREATE_CHASSIS), - ] - self.assertEqual(expect, self.api.calls) - self.assertTrue(chassis) - - def test_create_with_uuid(self): - chassis = self.mgr.create(**CREATE_WITH_UUID) - expect = [ - ('POST', '/v1/chassis', {}, CREATE_WITH_UUID), - ] - self.assertEqual(expect, self.api.calls) - self.assertTrue(chassis) - - def test_delete(self): - chassis = self.mgr.delete(chassis_id=CHASSIS['uuid']) - expect = [ - ('DELETE', '/v1/chassis/%s' % CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(chassis) - - def test_update(self): - patch = {'op': 'replace', - 'value': NEW_DESCR, - 'path': '/description'} - chassis = self.mgr.update(chassis_id=CHASSIS['uuid'], patch=patch) - expect = [ - ('PATCH', '/v1/chassis/%s' % CHASSIS['uuid'], {}, patch), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NEW_DESCR, chassis.description) - - def test_chassis_node_list(self): - nodes = self.mgr.list_nodes(CHASSIS['uuid']) - expect = [ - ('GET', '/v1/chassis/%s/nodes' % CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(nodes)) - self.assertEqual(NODE['uuid'], nodes[0].uuid) - - def test_chassis_node_list_detail(self): - nodes = self.mgr.list_nodes(CHASSIS['uuid'], detail=True) - expect = [ - ('GET', '/v1/chassis/%s/nodes/detail' % CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(nodes)) - self.assertEqual(NODE['uuid'], nodes[0].uuid) - - def test_chassis_node_list_fields(self): - nodes = self.mgr.list_nodes(CHASSIS['uuid'], fields=['uuid', 'extra']) - expect = [ - ('GET', '/v1/chassis/%s/nodes?fields=uuid,extra' % - CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(nodes)) - - def test_chassis_node_list_maintenance(self): - nodes = self.mgr.list_nodes(CHASSIS['uuid'], maintenance=False) - expect = [ - ('GET', '/v1/chassis/%s/nodes?maintenance=False' % - CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(nodes)) - - def test_chassis_node_list_associated(self): - nodes = self.mgr.list_nodes(CHASSIS['uuid'], associated=True) - expect = [ - ('GET', '/v1/chassis/%s/nodes?associated=True' % - CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(nodes)) - - def test_chassis_node_list_provision_state(self): - nodes = self.mgr.list_nodes(CHASSIS['uuid'], - provision_state="available") - expect = [ - ('GET', '/v1/chassis/%s/nodes?provision_state=available' % - CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(nodes)) - - def test_chassis_node_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, self.mgr.list_nodes, - CHASSIS['uuid'], detail=True, - fields=['uuid', 'extra']) - - def test_chassis_node_list_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - nodes = self.mgr.list_nodes(CHASSIS['uuid'], limit=1) - expect = [ - ('GET', - '/v1/chassis/%s/nodes?limit=1' % CHASSIS['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE['uuid'], nodes[0].uuid) - - def test_chassis_node_list_sort_key(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - nodes = self.mgr.list_nodes(CHASSIS['uuid'], sort_key='updated_at') - expect = [ - ('GET', - '/v1/chassis/%s/nodes?sort_key=updated_at' % CHASSIS['uuid'], {}, - None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE['uuid'], nodes[0].uuid) - - def test_chassis_node_list_sort_dir(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - nodes = self.mgr.list_nodes(CHASSIS['uuid'], sort_dir='desc') - expect = [ - ('GET', - '/v1/chassis/%s/nodes?sort_dir=desc' % CHASSIS['uuid'], {}, - None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE['uuid'], nodes[0].uuid) - - def test_chassis_node_list_marker(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.chassis.ChassisManager(self.api) - nodes = self.mgr.list_nodes(CHASSIS['uuid'], marker=NODE['uuid']) - expect = [ - ('GET', - '/v1/chassis/%s/nodes?marker=%s' % (CHASSIS['uuid'], - NODE['uuid']), {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE['uuid'], nodes[0].uuid) diff --git a/ironicclient/tests/unit/v1/test_chassis_shell.py b/ironicclient/tests/unit/v1/test_chassis_shell.py deleted file mode 100644 index a254ce9..0000000 --- a/ironicclient/tests/unit/v1/test_chassis_shell.py +++ /dev/null @@ -1,391 +0,0 @@ -# Copyright 2013 IBM Corp -# -# 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 mock - -from oslo_utils import uuidutils - -from ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common import utils as commonutils -from ironicclient.tests.unit import utils -import ironicclient.v1.chassis_shell as c_shell - - -class ChassisShellTest(utils.BaseTestCase): - def _get_client_mock_args(self, chassis=None, marker=None, limit=None, - sort_dir=None, sort_key=None, detail=False, - fields=None, associated=None, maintenance=None, - provision_state=None, json=False): - args = mock.MagicMock(spec=True) - args.chassis = chassis - args.marker = marker - args.limit = limit - args.sort_dir = sort_dir - args.sort_key = sort_key - args.detail = detail - args.fields = fields - args.associated = associated - args.maintenance = maintenance - args.provision_state = provision_state - args.json = json - - return args - - def test_chassis_show(self): - actual = {} - fake_print_dict = lambda data, *args, **kwargs: actual.update(data) - with mock.patch.object(cliutils, 'print_dict', fake_print_dict): - chassis = object() - c_shell._print_chassis_show(chassis) - exp = ['created_at', 'description', 'extra', 'updated_at', 'uuid'] - act = actual.keys() - self.assertEqual(sorted(exp), sorted(act)) - - def test_do_chassis_show_space_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis = ' ' - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_show, - client_mock, args) - - def test_do_chassis_show_empty_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis = '' - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_show, - client_mock, args) - - def test_do_chassis_show_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis = 'chassis_uuid' - args.fields = [['uuid', 'description']] - args.json = False - c_shell.do_chassis_show(client_mock, args) - client_mock.chassis.get.assert_called_once_with( - 'chassis_uuid', fields=['uuid', 'description']) - - def test_do_chassis_show_invalid_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis = 'chassis_uuid' - args.fields = [['foo', 'bar']] - args.json = False - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_show, - client_mock, args) - - def test_do_chassis_list(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args() - - c_shell.do_chassis_list(client_mock, args) - client_mock.chassis.list.assert_called_once_with(detail=False) - - def test_do_chassis_list_detail(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(detail=True) - - c_shell.do_chassis_list(client_mock, args) - client_mock.chassis.list.assert_called_once_with(detail=True) - - def test_do_chassis_list_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='created_at', - detail=False) - - c_shell.do_chassis_list(client_mock, args) - client_mock.chassis.list.assert_called_once_with(sort_key='created_at', - detail=False) - - def test_do_chassis_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='extra', - detail=False) - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_list, - client_mock, args) - self.assertFalse(client_mock.chassis.list.called) - - def test_do_chassis_list_detail_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='created_at', - detail=True) - - c_shell.do_chassis_list(client_mock, args) - client_mock.chassis.list.assert_called_once_with(sort_key='created_at', - detail=True) - - def test_do_chassis_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='extra', - detail=True) - - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_list, - client_mock, args) - self.assertFalse(client_mock.chassis.list.called) - - def test_do_chassis_list_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='desc', - detail=False) - - c_shell.do_chassis_list(client_mock, args) - client_mock.chassis.list.assert_called_once_with(sort_dir='desc', - detail=False) - - def test_do_chassis_list_detail_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='asc', - detail=True) - - c_shell.do_chassis_list(client_mock, args) - client_mock.chassis.list.assert_called_once_with(sort_dir='asc', - detail=True) - - def test_do_chassis_list_wrong_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='abc', - detail=False) - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_list, - client_mock, args) - self.assertFalse(client_mock.chassis.list.called) - - def test_do_chassis_list_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['uuid', 'description']]) - c_shell.do_chassis_list(client_mock, args) - client_mock.chassis.list.assert_called_once_with( - fields=['uuid', 'description'], detail=False) - - def test_do_chassis_list_invalid_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['foo', 'bar']]) - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_list, - client_mock, args) - - def test_do_chassis_node_list(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis=chassis_mock) - - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, detail=False) - - def test_do_chassis_node_list_details(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis=chassis_mock, detail=True) - - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, detail=True) - - def test_do_chassis_node_list_sort_key(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis_mock, sort_key='created_at', - detail=False) - - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, sort_key='created_at', detail=False) - - def test_do_chassis_node_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis_mock, sort_key='extra', - detail=False) - - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_node_list, - client_mock, args) - self.assertFalse(client_mock.chassis.list_nodes.called) - - def test_do_chassis_node_list_detail_sort_key(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis_mock, sort_key='created_at', - detail=True) - - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, sort_key='created_at', detail=True) - - def test_do_chassis_node_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis_mock, sort_key='extra', - detail=True) - - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_node_list, - client_mock, args) - self.assertFalse(client_mock.chassis.list_nodes.called) - - def test_do_chassis_node_list_sort_dir(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis_mock, sort_dir='desc', - detail=False) - - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, sort_dir='desc', detail=False) - - def test_do_chassis_node_list_detail_sort_dir(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis_mock, sort_dir='asc', - detail=True) - - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, sort_dir='asc', detail=True) - - def test_do_chassis_node_list_wrong_sort_dir(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis_mock, sort_dir='abc', - detail=False) - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_node_list, - client_mock, args) - self.assertFalse(client_mock.chassis.list_nodes.called) - - def test_do_chassis_node_list_fields(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis=chassis_mock, - fields=[['uuid', 'power_state']]) - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, fields=['uuid', 'power_state'], detail=False) - - def test_do_chassis_node_list_associated(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis=chassis_mock, - associated=True) - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, associated=True, detail=False) - - def test_do_chassis_node_list_maintenance(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis=chassis_mock, - maintenance=True) - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, maintenance=True, detail=False) - - def test_do_chassis_node_list_provision_state(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis=chassis_mock, - provision_state='wait call-back') - c_shell.do_chassis_node_list(client_mock, args) - client_mock.chassis.list_nodes.assert_called_once_with( - chassis_mock, provision_state='wait call-back', detail=False) - - def test_do_chassis_node_list_invalid_fields(self): - client_mock = mock.MagicMock() - chassis_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(chassis=chassis_mock, - fields=[['foo', 'bar']]) - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_node_list, client_mock, args) - - def test_do_chassis_create(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.json = False - c_shell.do_chassis_create(client_mock, args) - client_mock.chassis.create.assert_called_once_with() - - def test_do_chassis_create_with_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.uuid = uuidutils.generate_uuid() - args.json = False - - c_shell.do_chassis_create(client_mock, args) - client_mock.chassis.create.assert_called_once_with(uuid=args.uuid) - - def test_do_chassis_create_valid_field(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.extra = ["key1=val1", "key2=val2"] - args.description = 'desc' - args.json = False - c_shell.do_chassis_create(client_mock, args) - client_mock.chassis.create.assert_called_once_with(extra={ - 'key1': 'val1', - 'key2': 'val2'}, - description='desc') - - def test_do_chassis_create_wrong_extra_field(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.extra = ["foo"] - args.description = 'desc' - args.json = False - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_create, client_mock, args) - - def test_do_chassis_delete(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis = ['chassis_uuid'] - c_shell.do_chassis_delete(client_mock, args) - client_mock.chassis.delete.assert_called_once_with('chassis_uuid') - - def test_do_chassis_delete_multiple(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis = ['chassis_uuid1', 'chassis_uuid2'] - c_shell.do_chassis_delete(client_mock, args) - client_mock.chassis.delete.assert_has_calls([ - mock.call('chassis_uuid1'), mock.call('chassis_uuid2')]) - - def test_do_chassis_update(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis = 'chassis_uuid' - args.op = 'add' - args.attributes = [['arg1=val1', 'arg2=val2']] - args.json = False - c_shell.do_chassis_update(client_mock, args) - patch = commonutils.args_array_to_patch(args.op, args.attributes[0]) - client_mock.chassis.update.assert_called_once_with('chassis_uuid', - patch) - - def test_do_chassis_update_wrong_op(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis = 'chassis_uuid' - args.op = 'foo' - args.attributes = [['arg1=val1', 'arg2=val2']] - self.assertRaises(exceptions.CommandError, - c_shell.do_chassis_update, - client_mock, args) - self.assertFalse(client_mock.chassis.update.called) diff --git a/ironicclient/tests/unit/v1/test_client.py b/ironicclient/tests/unit/v1/test_client.py deleted file mode 100644 index 77c60dc..0000000 --- a/ironicclient/tests/unit/v1/test_client.py +++ /dev/null @@ -1,81 +0,0 @@ -# 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 mock - -from ironicclient.common import filecache -from ironicclient.common import http -from ironicclient import exc -from ironicclient.tests.unit import utils -from ironicclient.v1 import client - - -@mock.patch.object(http, '_construct_http_client', autospec=True) -class ClientTest(utils.BaseTestCase): - - def test_client_user_api_version(self, http_client_mock): - endpoint = 'http://ironic:6385' - token = 'safe_token' - os_ironic_api_version = '1.15' - - client.Client(endpoint, token=token, - os_ironic_api_version=os_ironic_api_version) - - http_client_mock.assert_called_once_with( - endpoint, token=token, - os_ironic_api_version=os_ironic_api_version, - api_version_select_state='user') - - @mock.patch.object(filecache, 'retrieve_data', autospec=True) - def test_client_cache_api_version(self, cache_mock, http_client_mock): - endpoint = 'http://ironic:6385' - token = 'safe_token' - os_ironic_api_version = '1.15' - cache_mock.return_value = os_ironic_api_version - - client.Client(endpoint, token=token) - - cache_mock.assert_called_once_with(host='ironic', port='6385') - http_client_mock.assert_called_once_with( - endpoint, token=token, - os_ironic_api_version=os_ironic_api_version, - api_version_select_state='cached') - - @mock.patch.object(filecache, 'retrieve_data', autospec=True) - def test_client_default_api_version(self, cache_mock, http_client_mock): - endpoint = 'http://ironic:6385' - token = 'safe_token' - cache_mock.return_value = None - - client.Client(endpoint, token=token) - - cache_mock.assert_called_once_with(host='ironic', port='6385') - http_client_mock.assert_called_once_with( - endpoint, token=token, - os_ironic_api_version=client.DEFAULT_VER, - api_version_select_state='default') - - def test_client_cache_version_no_endpoint_as_arg(self, http_client_mock): - self.assertRaises(exc.EndpointException, - client.Client, - session='fake_session', - insecure=True, - endpoint_override='http://ironic:6385') - - def test_client_initialized_managers(self, http_client_mock): - cl = client.Client('http://ironic:6385', token='safe_token', - os_ironic_api_version='1.15') - - self.assertIsInstance(cl.node, client.node.NodeManager) - self.assertIsInstance(cl.port, client.port.PortManager) - self.assertIsInstance(cl.driver, client.driver.DriverManager) - self.assertIsInstance(cl.chassis, client.chassis.ChassisManager) diff --git a/ironicclient/tests/unit/v1/test_create_resources.py b/ironicclient/tests/unit/v1/test_create_resources.py deleted file mode 100644 index 4b37934..0000000 --- a/ironicclient/tests/unit/v1/test_create_resources.py +++ /dev/null @@ -1,498 +0,0 @@ -# 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 jsonschema -import mock -import six -import six.moves.builtins as __builtin__ - -from ironicclient import exc -from ironicclient.tests.unit import utils -from ironicclient.v1 import create_resources - -valid_json = { - "chassis": [{ - "description": "testing resources import", - "nodes": [{ - "driver": "agent_ssh", - "extra": { - "kv1": True, - "vk1": None - }, - "properties": { - "a": "c" - }, - "ports": [{ - "address": "00:00:00:00:00:01", - "extra": { - "a": "b" - } - }], - "portgroups": [{ - "address": "00:00:00:00:00:02", - "name": "portgroup1", - "ports": [{ - "address": "00:00:00:00:00:03" - }] - }] - }] - }], - "nodes": [{ - "driver": "fake", - "driver_info": { - "fake_key": "fake", - "dict_prop": { - "a": "b" - }, - "arr_prop": [ - 1, 2, 3 - ] - }, - "chassis_uuid": "10f99593-b8c2-4fcb-8858-494c1a47cee6" - }] -} - -ironic_pov_invalid_json = { - "nodes": [{ - "driver": "non_existent", - "ports": [{ - "address": "invalid_address" - }] - }] -} - -schema_pov_invalid_json = {"meow": "woof!"} - - -class CreateSchemaTest(utils.BaseTestCase): - - def test_schema(self): - schema = create_resources._CREATE_SCHEMA - jsonschema.validate(valid_json, schema) - jsonschema.validate(ironic_pov_invalid_json, schema) - self.assertRaises(jsonschema.ValidationError, jsonschema.validate, - schema_pov_invalid_json, schema) - - -class CreateResourcesTest(utils.BaseTestCase): - - def setUp(self): - super(CreateResourcesTest, self).setUp() - self.client = mock.MagicMock() - - @mock.patch.object(create_resources, 'create_nodes', autospec=True) - @mock.patch.object(create_resources, 'create_chassis', autospec=True) - @mock.patch.object(jsonschema, 'validate', autospec=True) - @mock.patch.object(create_resources, 'load_from_file', - side_effect=[valid_json], autospec=True) - def test_create_resources( - self, mock_load, mock_validate, mock_chassis, mock_nodes): - resources_files = ['file.json'] - create_resources.create_resources(self.client, resources_files) - mock_load.assert_has_calls([ - mock.call('file.json') - ]) - mock_validate.assert_called_once_with(valid_json, mock.ANY) - mock_chassis.assert_called_once_with(self.client, - valid_json['chassis']) - mock_nodes.assert_called_once_with(self.client, - valid_json['nodes']) - - @mock.patch.object(create_resources, 'create_nodes', autospec=True) - @mock.patch.object(create_resources, 'create_chassis', autospec=True) - @mock.patch.object(jsonschema, 'validate', autospec=True) - @mock.patch.object(create_resources, 'load_from_file', - side_effect=exc.ClientException, autospec=True) - def test_create_resources_cannot_read_schema( - self, mock_load, mock_validate, mock_chassis, mock_nodes): - resources_files = ['file.json'] - self.assertRaises(exc.ClientException, - create_resources.create_resources, - self.client, resources_files) - mock_load.assert_called_once_with('file.json') - self.assertFalse(mock_validate.called) - self.assertFalse(mock_chassis.called) - self.assertFalse(mock_nodes.called) - - @mock.patch.object(create_resources, 'create_nodes', autospec=True) - @mock.patch.object(create_resources, 'create_chassis', autospec=True) - @mock.patch.object(jsonschema, 'validate', - side_effect=jsonschema.ValidationError(''), - autospec=True) - @mock.patch.object(create_resources, 'load_from_file', - side_effect=[schema_pov_invalid_json], autospec=True) - def test_create_resources_validation_fails( - self, mock_load, mock_validate, mock_chassis, mock_nodes): - resources_files = ['file.json'] - self.assertRaises(exc.ClientException, - create_resources.create_resources, - self.client, resources_files) - mock_load.assert_has_calls([ - mock.call('file.json') - ]) - mock_validate.assert_called_once_with(schema_pov_invalid_json, - mock.ANY) - self.assertFalse(mock_chassis.called) - self.assertFalse(mock_nodes.called) - - @mock.patch.object(create_resources, 'create_nodes', autospec=True) - @mock.patch.object(create_resources, 'create_chassis', autospec=True) - @mock.patch.object(jsonschema, 'validate', - side_effect=[None, jsonschema.ValidationError('')], - autospec=True) - @mock.patch.object(create_resources, 'load_from_file', - side_effect=[valid_json, schema_pov_invalid_json], - autospec=True) - def test_create_resources_validation_fails_multiple( - self, mock_load, mock_validate, mock_chassis, mock_nodes): - resources_files = ['file.json', 'file2.json'] - self.assertRaises(exc.ClientException, - create_resources.create_resources, - self.client, resources_files) - mock_load.assert_has_calls([ - mock.call('file.json'), mock.call('file2.json') - ]) - mock_validate.assert_has_calls([ - mock.call(valid_json, mock.ANY), - mock.call(schema_pov_invalid_json, mock.ANY) - ]) - self.assertFalse(mock_chassis.called) - self.assertFalse(mock_nodes.called) - - @mock.patch.object(create_resources, 'create_nodes', autospec=True) - @mock.patch.object(create_resources, 'create_chassis', autospec=True) - @mock.patch.object(jsonschema, 'validate', autospec=True) - @mock.patch.object(create_resources, 'load_from_file', - side_effect=[ironic_pov_invalid_json], autospec=True) - def test_create_resources_ironic_fails_to_create( - self, mock_load, mock_validate, mock_chassis, mock_nodes): - mock_nodes.return_value = [exc.ClientException('cannot create that')] - mock_chassis.return_value = [] - resources_files = ['file.json'] - self.assertRaises(exc.ClientException, - create_resources.create_resources, - self.client, resources_files) - mock_load.assert_has_calls([ - mock.call('file.json') - ]) - mock_validate.assert_called_once_with(ironic_pov_invalid_json, - mock.ANY) - mock_chassis.assert_called_once_with(self.client, []) - mock_nodes.assert_called_once_with( - self.client, ironic_pov_invalid_json['nodes']) - - -class LoadFromFileTest(utils.BaseTestCase): - - @mock.patch.object(__builtin__, 'open', - mock.mock_open(read_data='{"a": "b"}')) - def test_load_json(self): - fname = 'abc.json' - res = create_resources.load_from_file(fname) - self.assertEqual({'a': 'b'}, res) - - @mock.patch.object(__builtin__, 'open', - mock.mock_open(read_data='{"a": "b"}')) - def test_load_unknown_extension(self): - fname = 'abc' - self.assertRaisesRegex(exc.ClientException, - 'must have .json or .yaml extension', - create_resources.load_from_file, fname) - - @mock.patch.object(__builtin__, 'open', autospec=True) - def test_load_ioerror(self, mock_open): - mock_open.side_effect = IOError('file does not exist') - fname = 'abc.json' - self.assertRaisesRegex(exc.ClientException, - 'Cannot read file', - create_resources.load_from_file, fname) - - @mock.patch.object(__builtin__, 'open', - mock.mock_open(read_data='{{bbb')) - def test_load_incorrect_json(self): - fname = 'abc.json' - self.assertRaisesRegex( - exc.ClientException, 'File "%s" is invalid' % fname, - create_resources.load_from_file, fname) - - @mock.patch.object(__builtin__, 'open', - mock.mock_open(read_data='---\na: b')) - def test_load_yaml(self): - fname = 'abc.yaml' - res = create_resources.load_from_file(fname) - self.assertEqual({'a': 'b'}, res) - - @mock.patch.object(__builtin__, 'open', - mock.mock_open(read_data='---\na-: - b')) - def test_load_incorrect_yaml(self): - fname = 'abc.yaml' - self.assertRaisesRegex( - exc.ClientException, 'File "%s" is invalid' % fname, - create_resources.load_from_file, fname) - - -class CreateMethodsTest(utils.BaseTestCase): - - def setUp(self): - super(CreateMethodsTest, self).setUp() - self.client = mock.MagicMock() - - def test_create_single_node(self): - params = {'driver': 'fake'} - self.client.node.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual( - ('uuid', None), - create_resources.create_single_node(self.client, **params) - ) - self.client.node.create.assert_called_once_with(driver='fake') - - def test_create_single_node_with_ports(self): - params = {'driver': 'fake', 'ports': ['some ports here']} - self.client.node.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual( - ('uuid', None), - create_resources.create_single_node(self.client, **params) - ) - self.client.node.create.assert_called_once_with(driver='fake') - - def test_create_single_node_with_portgroups(self): - params = {'driver': 'fake', 'portgroups': ['some portgroups']} - self.client.node.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual( - ('uuid', None), - create_resources.create_single_node(self.client, **params) - ) - self.client.node.create.assert_called_once_with(driver='fake') - - def test_create_single_node_raises_client_exception(self): - params = {'driver': 'fake'} - e = exc.ClientException('foo') - self.client.node.create.side_effect = e - res, err = create_resources.create_single_node(self.client, **params) - self.assertIsNone(res) - self.assertIsInstance(err, exc.ClientException) - self.assertIn('Unable to create the node', str(err)) - self.client.node.create.assert_called_once_with(driver='fake') - - def test_create_single_node_raises_invalid_exception(self): - params = {'driver': 'fake'} - e = exc.InvalidAttribute('foo') - self.client.node.create.side_effect = e - res, err = create_resources.create_single_node(self.client, **params) - self.assertIsNone(res) - self.assertIsInstance(err, exc.InvalidAttribute) - self.assertIn('Cannot create the node with attributes', str(err)) - self.client.node.create.assert_called_once_with(driver='fake') - - def test_create_single_port(self): - params = {'address': 'fake-address', 'node_uuid': 'fake-node-uuid'} - self.client.port.create.return_value = mock.Mock(uuid='fake-port-uuid') - self.assertEqual( - ('fake-port-uuid', None), - create_resources.create_single_port(self.client, **params) - ) - self.client.port.create.assert_called_once_with(**params) - - def test_create_single_portgroup(self): - params = {'address': 'fake-address', 'node_uuid': 'fake-node-uuid'} - self.client.portgroup.create.return_value = mock.Mock( - uuid='fake-portgroup-uuid') - self.assertEqual( - ('fake-portgroup-uuid', None), - create_resources.create_single_portgroup(self.client, **params) - ) - self.client.portgroup.create.assert_called_once_with(**params) - - def test_create_single_portgroup_with_ports(self): - params = {'ports': ['some ports'], 'node_uuid': 'fake-node-uuid'} - self.client.portgroup.create.return_value = mock.Mock( - uuid='fake-portgroup-uuid') - self.assertEqual( - ('fake-portgroup-uuid', None), - create_resources.create_single_portgroup( - self.client, **params) - ) - self.client.portgroup.create.assert_called_once_with( - node_uuid='fake-node-uuid') - - def test_create_single_chassis(self): - self.client.chassis.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual( - ('uuid', None), - create_resources.create_single_chassis(self.client) - ) - self.client.chassis.create.assert_called_once_with() - - def test_create_single_chassis_with_nodes(self): - params = {'nodes': ['some nodes here']} - self.client.chassis.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual( - ('uuid', None), - create_resources.create_single_chassis(self.client, **params) - ) - self.client.chassis.create.assert_called_once_with() - - def test_create_ports(self): - port = {'address': 'fake-address'} - port_with_node_uuid = port.copy() - port_with_node_uuid.update(node_uuid='fake-node-uuid') - self.client.port.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual([], create_resources.create_ports(self.client, [port], - 'fake-node-uuid')) - self.client.port.create.assert_called_once_with(**port_with_node_uuid) - - def test_create_ports_two_node_uuids(self): - port = {'address': 'fake-address', 'node_uuid': 'node-uuid-1'} - errs = create_resources.create_ports(self.client, [port], - 'node-uuid-2') - self.assertIsInstance(errs[0], exc.ClientException) - self.assertEqual(1, len(errs)) - self.assertFalse(self.client.port.create.called) - - def test_create_ports_two_portgroup_uuids(self): - port = {'address': 'fake-address', 'node_uuid': 'node-uuid-1', - 'portgroup_uuid': 'pg-uuid-1'} - errs = create_resources.create_ports(self.client, [port], - 'node-uuid-1', 'pg-uuid-2') - self.assertEqual(1, len(errs)) - self.assertIsInstance(errs[0], exc.ClientException) - self.assertIn('port group', six.text_type(errs[0])) - self.assertFalse(self.client.port.create.called) - - @mock.patch.object(create_resources, 'create_portgroups', autospec=True) - @mock.patch.object(create_resources, 'create_ports', autospec=True) - def test_create_nodes(self, mock_create_ports, mock_create_portgroups): - node = {'driver': 'fake', 'ports': ['list of ports'], - 'portgroups': ['list of portgroups']} - self.client.node.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual([], create_resources.create_nodes(self.client, - [node])) - self.client.node.create.assert_called_once_with(driver='fake') - mock_create_ports.assert_called_once_with( - self.client, ['list of ports'], node_uuid='uuid') - mock_create_portgroups.assert_called_once_with( - self.client, ['list of portgroups'], node_uuid='uuid') - - @mock.patch.object(create_resources, 'create_portgroups', autospec=True) - @mock.patch.object(create_resources, 'create_ports', autospec=True) - def test_create_nodes_exception(self, mock_create_ports, - mock_create_portgroups): - node = {'driver': 'fake', 'ports': ['list of ports'], - 'portgroups': ['list of portgroups']} - self.client.node.create.side_effect = exc.ClientException('bar') - errs = create_resources.create_nodes(self.client, [node]) - self.assertIsInstance(errs[0], exc.ClientException) - self.assertEqual(1, len(errs)) - self.client.node.create.assert_called_once_with(driver='fake') - self.assertFalse(mock_create_ports.called) - self.assertFalse(mock_create_portgroups.called) - - @mock.patch.object(create_resources, 'create_ports', autospec=True) - def test_create_nodes_two_chassis_uuids(self, mock_create_ports): - node = {'driver': 'fake', 'ports': ['list of ports'], - 'chassis_uuid': 'chassis-uuid-1'} - errs = create_resources.create_nodes(self.client, [node], - chassis_uuid='chassis-uuid-2') - self.assertFalse(self.client.node.create.called) - self.assertFalse(mock_create_ports.called) - self.assertEqual(1, len(errs)) - self.assertIsInstance(errs[0], exc.ClientException) - - @mock.patch.object(create_resources, 'create_portgroups', autospec=True) - @mock.patch.object(create_resources, 'create_ports', autospec=True) - def test_create_nodes_no_ports_portgroups(self, mock_create_ports, - mock_create_portgroups): - node = {'driver': 'fake'} - self.client.node.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual([], create_resources.create_nodes(self.client, - [node])) - self.client.node.create.assert_called_once_with(driver='fake') - self.assertFalse(mock_create_ports.called) - self.assertFalse(mock_create_portgroups.called) - - @mock.patch.object(create_resources, 'create_nodes', autospec=True) - def test_create_chassis(self, mock_create_nodes): - chassis = {'description': 'fake', 'nodes': ['list of nodes']} - self.client.chassis.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual([], create_resources.create_chassis(self.client, - [chassis])) - self.client.chassis.create.assert_called_once_with(description='fake') - mock_create_nodes.assert_called_once_with( - self.client, ['list of nodes'], chassis_uuid='uuid') - - @mock.patch.object(create_resources, 'create_nodes', autospec=True) - def test_create_chassis_exception(self, mock_create_nodes): - chassis = {'description': 'fake', 'nodes': ['list of nodes']} - self.client.chassis.create.side_effect = exc.ClientException('bar') - errs = create_resources.create_chassis(self.client, [chassis]) - self.client.chassis.create.assert_called_once_with(description='fake') - self.assertFalse(mock_create_nodes.called) - self.assertEqual(1, len(errs)) - self.assertIsInstance(errs[0], exc.ClientException) - - @mock.patch.object(create_resources, 'create_nodes', autospec=True) - def test_create_chassis_no_nodes(self, mock_create_nodes): - chassis = {'description': 'fake'} - self.client.chassis.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual([], create_resources.create_chassis(self.client, - [chassis])) - self.client.chassis.create.assert_called_once_with(description='fake') - self.assertFalse(mock_create_nodes.called) - - @mock.patch.object(create_resources, 'create_ports', autospec=True) - def test_create_portgroups(self, mock_create_ports): - portgroup = {'name': 'fake', 'ports': ['list of ports']} - portgroup_posted = {'name': 'fake', 'node_uuid': 'fake-node-uuid'} - self.client.portgroup.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual([], create_resources.create_portgroups( - self.client, [portgroup], node_uuid='fake-node-uuid')) - self.client.portgroup.create.assert_called_once_with( - **portgroup_posted) - mock_create_ports.assert_called_once_with( - self.client, ['list of ports'], node_uuid='fake-node-uuid', - portgroup_uuid='uuid') - - @mock.patch.object(create_resources, 'create_ports', autospec=True) - def test_create_portgroups_exception(self, mock_create_ports): - portgroup = {'name': 'fake', 'ports': ['list of ports']} - portgroup_posted = {'name': 'fake', 'node_uuid': 'fake-node-uuid'} - self.client.portgroup.create.side_effect = exc.ClientException('bar') - errs = create_resources.create_portgroups( - self.client, [portgroup], node_uuid='fake-node-uuid') - self.client.portgroup.create.assert_called_once_with( - **portgroup_posted) - self.assertFalse(mock_create_ports.called) - self.assertEqual(1, len(errs)) - self.assertIsInstance(errs[0], exc.ClientException) - - @mock.patch.object(create_resources, 'create_ports', autospec=True) - def test_create_portgroups_two_node_uuids(self, mock_create_ports): - portgroup = {'name': 'fake', 'node_uuid': 'fake-node-uuid-1', - 'ports': ['list of ports']} - self.client.portgroup.create.side_effect = exc.ClientException('bar') - errs = create_resources.create_portgroups( - self.client, [portgroup], node_uuid='fake-node-uuid-2') - self.assertFalse(self.client.portgroup.create.called) - self.assertFalse(mock_create_ports.called) - self.assertEqual(1, len(errs)) - self.assertIsInstance(errs[0], exc.ClientException) - - @mock.patch.object(create_resources, 'create_ports', autospec=True) - def test_create_portgroups_no_ports(self, mock_create_ports): - portgroup = {'name': 'fake'} - portgroup_posted = {'name': 'fake', 'node_uuid': 'fake-node-uuid'} - self.client.portgroup.create.return_value = mock.Mock(uuid='uuid') - self.assertEqual([], create_resources.create_portgroups( - self.client, [portgroup], node_uuid='fake-node-uuid')) - self.client.portgroup.create.assert_called_once_with( - **portgroup_posted) - self.assertFalse(mock_create_ports.called) diff --git a/ironicclient/tests/unit/v1/test_create_resources_shell.py b/ironicclient/tests/unit/v1/test_create_resources_shell.py deleted file mode 100644 index 87a9320..0000000 --- a/ironicclient/tests/unit/v1/test_create_resources_shell.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 mock - -from ironicclient.tests.unit import utils -from ironicclient.v1 import create_resources -from ironicclient.v1 import create_resources_shell - - -class TestCreateResourcesShell(utils.BaseTestCase): - def setUp(self): - super(TestCreateResourcesShell, self).setUp() - self.client = mock.MagicMock(autospec=True) - - @mock.patch.object(create_resources, 'create_resources', autospec=True) - def test_create_shell(self, mock_create_resources): - args = mock.MagicMock() - files = ['file1', 'file2', 'file3'] - args.resource_files = files - create_resources_shell.do_create(self.client, args) - mock_create_resources.assert_called_once_with(self.client, files) diff --git a/ironicclient/tests/unit/v1/test_driver.py b/ironicclient/tests/unit/v1/test_driver.py deleted file mode 100644 index 388b9f7..0000000 --- a/ironicclient/tests/unit/v1/test_driver.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright 2013 Red Hat, 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 mock -import testtools -from testtools import matchers - -from ironicclient import exc -from ironicclient.tests.unit import utils -from ironicclient.v1 import driver - - -DRIVER1 = { - 'name': 'fake', - 'type': 'dynamic', - 'hosts': ['fake-host1', 'fake-host2'], - 'default_boot_interface': 'boot', - 'default_console_interface': 'console', - 'default_deploy_interface': 'deploy', - 'default_inspect_interface': 'inspect', - 'default_management_interface': 'management', - 'default_network_interface': 'network', - 'default_power_interface': 'power', - 'default_raid_interface': 'raid', - 'default_vendor_interface': 'vendor', - 'enabled_boot_interfaces': ['boot', 'boot2'], - 'enabled_console_interfaces': ['console', 'console2'], - 'enabled_deploy_interfaces': ['deploy', 'deploy2'], - 'enabled_inspect_interfaces': ['inspect', 'inspect2'], - 'enabled_management_interfaces': ['management', 'management2'], - 'enabled_network_interfaces': ['network', 'network2'], - 'enabled_power_interfaces': ['power', 'power2'], - 'enabled_raid_interfaces': ['raid', 'raid2'], - 'enabled_vendor_interfaces': ['vendor', 'vendor2'], -} -DRIVER2 = { - 'name': 'pxe_ipminative', - 'type': 'classic', - 'hosts': ['fake-host1', 'fake-host2'], -} - -DRIVER2_PROPERTIES = { - "username": "username. Required.", - "password": "password. Optional.", - "address": "IP of the node. Required.", -} - -DRIVER_VENDOR_PASSTHRU_METHOD = {"lookup": {"attach": "false", - "http_methods": ["POST"], - "description": "", - "async": "false"}} -DRIVER2_RAID_LOGICAL_DISK_PROPERTIES = { - "property1": "description1", - "property2": "description2", -} - -fake_responses = { - '/v1/drivers': - { - 'GET': ( - {}, - {'drivers': [DRIVER1]}, - ), - }, - '/v1/drivers/%s' % DRIVER1['name']: - { - 'GET': ( - {}, - DRIVER1 - ), - }, - '/v1/drivers/%s/properties' % DRIVER2['name']: - { - 'GET': ( - {}, - DRIVER2_PROPERTIES, - ), - }, - '/v1/drivers/%s/vendor_passthru/methods' % DRIVER1['name']: - { - 'GET': ( - {}, - DRIVER_VENDOR_PASSTHRU_METHOD, - ), - }, - '/v1/drivers/%s/raid/logical_disk_properties' % DRIVER2['name']: - { - 'GET': ( - {}, - DRIVER2_RAID_LOGICAL_DISK_PROPERTIES, - ), - }, -} - - -class DriverManagerTest(testtools.TestCase): - - def setUp(self): - super(DriverManagerTest, self).setUp() - self.api = utils.FakeAPI(fake_responses) - self.mgr = driver.DriverManager(self.api) - - def test_driver_list(self): - drivers = self.mgr.list() - expect = [ - ('GET', '/v1/drivers', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(drivers, matchers.HasLength(1)) - - def test_driver_show(self): - driver_ = self.mgr.get(DRIVER1['name']) - expect = [ - ('GET', '/v1/drivers/%s' % DRIVER1['name'], {}, None) - ] - self.assertEqual(expect, self.api.calls) - - driver_attr = {} - for attr in DRIVER1.keys(): - driver_attr[attr] = getattr(driver_, attr) - - self.assertEqual(DRIVER1, driver_attr) - - def test_driver_properties(self): - properties = self.mgr.properties(DRIVER2['name']) - expect = [ - ('GET', '/v1/drivers/%s/properties' % DRIVER2['name'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(DRIVER2_PROPERTIES, properties) - - def test_driver_raid_logical_disk_properties(self): - properties = self.mgr.raid_logical_disk_properties(DRIVER2['name']) - expect = [ - ('GET', - '/v1/drivers/%s/raid/logical_disk_properties' % DRIVER2['name'], - {}, None)] - self.assertEqual(expect, self.api.calls) - self.assertEqual(DRIVER2_RAID_LOGICAL_DISK_PROPERTIES, properties) - - @mock.patch.object(driver.DriverManager, '_list', autospec=True) - def test_driver_raid_logical_disk_properties_indexerror(self, _list_mock): - _list_mock.side_effect = IndexError - - properties = self.mgr.raid_logical_disk_properties(DRIVER2['name']) - - _list_mock.assert_called_once_with( - self.mgr, - '/v1/drivers/%s/raid/logical_disk_properties' % DRIVER2['name']) - self.assertEqual({}, properties) - - @mock.patch.object(driver.DriverManager, 'update', autospec=True) - def test_vendor_passthru_update(self, update_mock): - # For now just mock the tests because vendor-passthru doesn't return - # anything to verify. - vendor_passthru_args = {'arg1': 'val1'} - kwargs = { - 'driver_name': 'driver_name', - 'method': 'method', - 'args': vendor_passthru_args - } - - final_path = 'driver_name/vendor_passthru/method' - for http_method in ('POST', 'PUT', 'PATCH'): - kwargs['http_method'] = http_method - self.mgr.vendor_passthru(**kwargs) - update_mock.assert_called_once_with(mock.ANY, final_path, - vendor_passthru_args, - http_method=http_method) - update_mock.reset_mock() - - @mock.patch.object(driver.DriverManager, 'get', autospec=True) - def test_vendor_passthru_get(self, get_mock): - kwargs = { - 'driver_name': 'driver_name', - 'method': 'method', - 'http_method': 'GET', - } - - final_path = 'driver_name/vendor_passthru/method' - self.mgr.vendor_passthru(**kwargs) - get_mock.assert_called_once_with(mock.ANY, final_path) - - @mock.patch.object(driver.DriverManager, 'delete', autospec=True) - def test_vendor_passthru_delete(self, delete_mock): - kwargs = { - 'driver_name': 'driver_name', - 'method': 'method', - 'http_method': 'DELETE', - } - - final_path = 'driver_name/vendor_passthru/method' - self.mgr.vendor_passthru(**kwargs) - delete_mock.assert_called_once_with(mock.ANY, final_path) - - @mock.patch.object(driver.DriverManager, 'delete', autospec=True) - def test_vendor_passthru_unknown_http_method(self, delete_mock): - kwargs = { - 'driver_name': 'driver_name', - 'method': 'method', - 'http_method': 'UNKNOWN', - } - self.assertRaises(exc.InvalidAttribute, self.mgr.vendor_passthru, - **kwargs) - - def test_vendor_passthru_methods(self): - vendor_methods = self.mgr.get_vendor_passthru_methods(DRIVER1['name']) - expect = [ - ('GET', '/v1/drivers/%s/vendor_passthru/methods' % DRIVER1['name'], - {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(DRIVER_VENDOR_PASSTHRU_METHOD, vendor_methods) diff --git a/ironicclient/tests/unit/v1/test_driver_shell.py b/ironicclient/tests/unit/v1/test_driver_shell.py deleted file mode 100644 index aecf570..0000000 --- a/ironicclient/tests/unit/v1/test_driver_shell.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# -# 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 mock - -from ironicclient.common import cliutils -from ironicclient.tests.unit import utils -import ironicclient.v1.driver as v1_driver -import ironicclient.v1.driver_shell as d_shell - - -class DriverShellTest(utils.BaseTestCase): - def setUp(self): - super(DriverShellTest, self).setUp() - client_mock = mock.MagicMock() - driver_mock = mock.MagicMock(spec=v1_driver.DriverManager) - client_mock.driver = driver_mock - self.client_mock = client_mock - - def test_driver_show(self): - actual = {} - fake_print_dict = lambda data, *args, **kwargs: actual.update(data) - with mock.patch.object(cliutils, 'print_dict', fake_print_dict): - driver = object() - d_shell._print_driver_show(driver) - exp = ['hosts', 'name', 'type', - 'default_boot_interface', 'default_console_interface', - 'default_deploy_interface', 'default_inspect_interface', - 'default_management_interface', 'default_network_interface', - 'default_power_interface', 'default_raid_interface', - 'default_storage_interface', 'default_vendor_interface', - 'enabled_boot_interfaces', 'enabled_console_interfaces', - 'enabled_deploy_interfaces', 'enabled_inspect_interfaces', - 'enabled_management_interfaces', 'enabled_network_interfaces', - 'enabled_power_interfaces', 'enabled_raid_interfaces', - 'enabled_storage_interfaces', 'enabled_vendor_interfaces'] - act = actual.keys() - self.assertEqual(sorted(exp), sorted(act)) - - def test_do_driver_vendor_passthru_with_args(self): - client_mock = self.client_mock - args = mock.MagicMock() - args.driver_name = 'driver_name' - args.http_method = 'POST' - args.method = 'method' - args.arguments = [['arg1=val1', 'arg2=val2']] - - d_shell.do_driver_vendor_passthru(client_mock, args) - client_mock.driver.vendor_passthru.assert_called_once_with( - args.driver_name, args.method, http_method=args.http_method, - args={'arg1': 'val1', 'arg2': 'val2'}) - - def test_do_driver_vendor_passthru_without_args(self): - client_mock = self.client_mock - args = mock.MagicMock() - args.driver_name = 'driver_name' - args.http_method = 'POST' - args.method = 'method' - args.arguments = [[]] - - d_shell.do_driver_vendor_passthru(client_mock, args) - client_mock.driver.vendor_passthru.assert_called_once_with( - args.driver_name, args.method, args={}, - http_method=args.http_method) - - def test_do_driver_properties(self): - client_mock = self.client_mock - args = mock.MagicMock() - args.driver_name = 'driver_name' - args.json = False - - d_shell.do_driver_properties(client_mock, args) - client_mock.driver.properties.assert_called_once_with("driver_name") - - @mock.patch('ironicclient.common.cliutils.print_dict', autospec=True) - def test_do_driver_properties_with_wrap_default(self, mock_print_dict): - client_mock = self.client_mock - client_mock.driver.properties.return_value = { - 'foo': 'bar', - 'baz': 'qux'} - args = mock.MagicMock() - args.driver_name = 'driver_name' - args.wrap = 0 - args.json = False - - d_shell.do_driver_properties(client_mock, args) - mock_print_dict.assert_called_with( - {'foo': 'bar', 'baz': 'qux'}, - dict_value='Description', - json_flag=False, - wrap=0) - - @mock.patch('ironicclient.common.cliutils.print_dict', autospec=True) - def test_do_driver_properties_with_wrap(self, mock_print_dict): - client_mock = self.client_mock - client_mock.driver.properties.return_value = { - 'foo': 'bar', - 'baz': 'qux'} - args = mock.MagicMock() - args.driver_name = 'driver_name' - args.wrap = 80 - args.json = False - - d_shell.do_driver_properties(client_mock, args) - mock_print_dict.assert_called_with( - {'foo': 'bar', 'baz': 'qux'}, - dict_value='Description', - json_flag=False, - wrap=80) - - @mock.patch('ironicclient.common.cliutils.print_dict', autospec=True) - def _test_do_driver_raid_logical_disk(self, print_dict_mock, wrap=0): - cli_mock = self.client_mock - cli_mock.driver.raid_logical_disk_properties.return_value = { - 'foo': 'bar'} - args = mock.MagicMock() - args.driver_name = 'driver_name' - args.wrap = wrap - - d_shell.do_driver_raid_logical_disk_properties(cli_mock, args) - - cli_mock.driver.raid_logical_disk_properties.assert_called_once_with( - "driver_name") - print_dict_mock.assert_called_with( - {'foo': 'bar'}, - dict_value='Description', - wrap=wrap) - - def test_do_driver_raid_logical_disk_default_wrap(self): - self._test_do_driver_raid_logical_disk() - - def test_do_driver_raid_logical_disk_with_wrap(self): - self._test_do_driver_raid_logical_disk(wrap=80) - - def test_do_driver_show(self): - client_mock = self.client_mock - args = mock.MagicMock() - args.driver_name = 'fake' - args.json = False - - d_shell.do_driver_show(client_mock, args) - client_mock.driver.get.assert_called_once_with('fake') - - def test_do_driver_list(self): - client_mock = self.client_mock - args = mock.MagicMock() - args.type = None - args.detail = None - args.json = False - - d_shell.do_driver_list(client_mock, args) - client_mock.driver.list.assert_called_once_with(driver_type=None, - detail=None) - - def test_do_driver_list_with_type_and_no_detail(self): - client_mock = self.client_mock - args = mock.MagicMock() - args.type = 'classic' - args.detail = False - args.json = False - - d_shell.do_driver_list(client_mock, args) - client_mock.driver.list.assert_called_once_with(driver_type='classic', - detail=False) - - def test_do_driver_list_with_detail(self): - client_mock = self.client_mock - args = mock.MagicMock() - args.type = None - args.detail = True - args.json = False - - d_shell.do_driver_list(client_mock, args) - client_mock.driver.list.assert_called_once_with(driver_type=None, - detail=True) - - def test_do_driver_get_vendor_passthru_methods(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.driver_name = 'fake' - d_shell.do_driver_get_vendor_passthru_methods(client_mock, args) - mock_method = client_mock.driver.get_vendor_passthru_methods - mock_method.assert_called_once_with('fake') diff --git a/ironicclient/tests/unit/v1/test_node.py b/ironicclient/tests/unit/v1/test_node.py deleted file mode 100644 index aa1ceaf..0000000 --- a/ironicclient/tests/unit/v1/test_node.py +++ /dev/null @@ -1,1642 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# -# 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 copy -import tempfile -import time - -import mock -import six -import testtools -from testtools.matchers import HasLength - -from ironicclient.common import utils as common_utils -from ironicclient import exc -from ironicclient.tests.unit import utils -from ironicclient.v1 import node -from ironicclient.v1 import volume_connector -from ironicclient.v1 import volume_target - -if six.PY3: - import io - file = io.BytesIO - -NODE1 = {'uuid': '66666666-7777-8888-9999-000000000000', - 'chassis_uuid': 'aaaaaaaa-1111-bbbb-2222-cccccccccccc', - 'maintenance': False, - 'provision_state': 'available', - 'driver': 'fake', - 'driver_info': {'user': 'foo', 'password': 'bar'}, - 'properties': {'num_cpu': 4}, - 'name': 'fake-node-1', - 'resource_class': 'foo', - 'extra': {}} -NODE2 = {'uuid': '66666666-7777-8888-9999-111111111111', - 'instance_uuid': '66666666-7777-8888-9999-222222222222', - 'chassis_uuid': 'aaaaaaaa-1111-bbbb-2222-cccccccccccc', - 'maintenance': True, - 'driver': 'fake too', - 'driver_info': {'user': 'foo', 'password': 'bar'}, - 'properties': {'num_cpu': 4}, - 'resource_class': 'bar', - 'extra': {}} -PORT = {'uuid': '11111111-2222-3333-4444-555555555555', - 'node_uuid': '66666666-7777-8888-9999-000000000000', - 'address': 'AA:AA:AA:AA:AA:AA', - 'extra': {}} -PORTGROUP = {'uuid': '11111111-2222-3333-4444-555555555555', - 'name': 'Portgroup', - 'node_uuid': '66666666-7777-8888-9999-000000000000', - 'address': 'AA:BB:CC:DD:EE:FF', - 'extra': {}} -CONNECTOR = {'uuid': 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', - 'node_uuid': NODE1['uuid'], - 'type': 'iqn', - 'connector_id': 'iqn.2010-10.org.openstack:test', - 'extra': {}} -TARGET = {'uuid': 'cccccccc-dddd-eeee-ffff-000000000000', - 'node_uuid': NODE1['uuid'], - 'volume_type': 'iscsi', - 'properties': {'target_iqn': 'iqn.foo'}, - 'boot_index': 0, - 'volume_id': '12345678', - 'extra': {}} - - -POWER_STATE = {'power_state': 'power on', - 'target_power_state': 'power off'} - -DRIVER_IFACES = {'deploy': {'result': True}, - 'power': {'result': False, 'reason': 'Invalid IPMI username'}, - 'console': {'result': None, 'reason': 'not supported'}, - 'rescue': {'result': None, 'reason': 'not supported'}} - -NODE_STATES = {"last_error": None, - "power_state": "power on", - "provision_state": "active", - "target_power_state": None, - "target_provision_state": None} - -CONSOLE_DATA_ENABLED = {'console_enabled': True, - 'console_info': {'test-console': 'test-console-data'}} -CONSOLE_DATA_DISABLED = {'console_enabled': False, 'console_info': None} - -CONSOLE_ENABLE = 'true' - -BOOT_DEVICE = {'boot_device': 'pxe', 'persistent': False} -SUPPORTED_BOOT_DEVICE = {'supported_boot_devices': ['pxe']} - -NODE_VENDOR_PASSTHRU_METHOD = {"heartbeat": {"attach": "false", - "http_methods": ["POST"], - "description": "", - "async": "true"}} - -VIFS = {'vifs': [{'id': 'aaa-aaa'}]} - -CREATE_NODE = copy.deepcopy(NODE1) -del CREATE_NODE['uuid'] -del CREATE_NODE['maintenance'] -del CREATE_NODE['provision_state'] - -UPDATED_NODE = copy.deepcopy(NODE1) -NEW_DRIVER = 'new-driver' -UPDATED_NODE['driver'] = NEW_DRIVER - -CREATE_WITH_UUID = copy.deepcopy(NODE1) -del CREATE_WITH_UUID['maintenance'] -del CREATE_WITH_UUID['provision_state'] - -fake_responses = { - '/v1/nodes': - { - 'GET': ( - {}, - {"nodes": [NODE1, NODE2]} - ), - 'POST': ( - {}, - CREATE_NODE, - ), - }, - '/v1/nodes/detail': - { - 'GET': ( - {}, - {"nodes": [NODE1, NODE2]} - ), - }, - '/v1/nodes/?fields=uuid,extra': - { - 'GET': ( - {}, - {"nodes": [NODE1]} - ), - }, - '/v1/nodes/?associated=False': - { - 'GET': ( - {}, - {"nodes": [NODE1]}, - ) - }, - '/v1/nodes/?associated=True': - { - 'GET': ( - {}, - {"nodes": [NODE2]}, - ) - }, - '/v1/nodes/?maintenance=False': - { - 'GET': ( - {}, - {"nodes": [NODE1]}, - ) - }, - '/v1/nodes/?maintenance=True': - { - 'GET': ( - {}, - {"nodes": [NODE2]}, - ) - }, - '/v1/nodes/?associated=True&maintenance=True': - { - 'GET': ( - {}, - {"nodes": [NODE2]}, - ) - }, - '/v1/nodes/?provision_state=available': - { - 'GET': ( - {}, - {"nodes": [NODE1]}, - ) - }, - '/v1/nodes/?driver=fake': - { - 'GET': ( - {}, - {"nodes": [NODE1]}, - ) - }, - '/v1/nodes/?resource_class=foo': - { - 'GET': ( - {}, - {"nodes": [NODE1]}, - ) - }, - '/v1/nodes/?chassis_uuid=%s' % NODE2['chassis_uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE2]}, - ) - }, - '/v1/nodes/detail?instance_uuid=%s' % NODE2['instance_uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE2]}, - ) - }, - '/v1/nodes/%s' % NODE1['uuid']: - { - 'GET': ( - {}, - NODE1, - ), - 'DELETE': ( - {}, - None, - ), - 'PATCH': ( - {}, - UPDATED_NODE, - ), - }, - '/v1/nodes/%s?fields=uuid,extra' % NODE1['uuid']: - { - 'GET': ( - {}, - NODE1, - ), - }, - '/v1/nodes/%s' % NODE2['uuid']: - { - 'GET': ( - {}, - NODE2, - ), - }, - '/v1/nodes/%s' % NODE1['name']: - { - 'GET': ( - {}, - NODE1, - ), - }, - '/v1/nodes/%s/ports' % NODE1['uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/ports' % NODE1['name']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/ports/detail' % NODE1['uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/ports/detail' % NODE1['name']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/ports?fields=uuid,address' % NODE1['uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/portgroups' % NODE1['uuid']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/nodes/%s/portgroups/detail' % NODE1['uuid']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/nodes/%s/portgroups?fields=uuid,address' % NODE1['uuid']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/nodes/%s/volume/connectors' % NODE1['uuid']: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR]}, - ), - }, - '/v1/nodes/%s/volume/connectors?detail=True' % NODE1['uuid']: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR]}, - ), - }, - '/v1/nodes/%s/volume/connectors?fields=uuid,connector_id' % NODE1['uuid']: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR]}, - ), - }, '/v1/nodes/%s/volume/targets' % NODE1['uuid']: - { - 'GET': ( - {}, - {"targets": [TARGET]}, - ), - }, - '/v1/nodes/%s/volume/targets?detail=True' % NODE1['uuid']: - { - 'GET': ( - {}, - {"targets": [TARGET]}, - ), - }, - '/v1/nodes/%s/volume/targets?fields=uuid,value' % NODE1['uuid']: - { - 'GET': ( - {}, - {"targets": [TARGET]}, - ), - }, - '/v1/nodes/%s/maintenance' % NODE1['uuid']: - { - 'PUT': ( - {}, - None, - ), - 'DELETE': ( - {}, - None, - ), - }, - '/v1/nodes/%s/states/power' % NODE1['uuid']: - { - 'PUT': ( - {}, - POWER_STATE, - ), - }, - '/v1/nodes/%s/validate' % NODE1['uuid']: - { - 'GET': ( - {}, - DRIVER_IFACES, - ), - }, - '/v1/nodes/%s/states/provision' % NODE1['uuid']: - { - 'PUT': ( - {}, - None, - ), - }, - '/v1/nodes/%s/states' % NODE1['uuid']: - { - 'GET': ( - {}, - NODE_STATES, - ), - }, - '/v1/nodes/%s/states/raid' % NODE1['uuid']: - { - 'PUT': ( - {}, - None, - ), - }, - '/v1/nodes/%s/states/console' % NODE1['uuid']: - { - 'GET': ( - {}, - CONSOLE_DATA_ENABLED, - ), - 'PUT': ( - {'enabled': CONSOLE_ENABLE}, - None, - ), - }, - '/v1/nodes/%s/states/console' % NODE2['uuid']: - { - 'GET': ( - {}, - CONSOLE_DATA_DISABLED, - ), - }, - '/v1/nodes/%s/management/boot_device' % NODE1['uuid']: - { - 'GET': ( - {}, - BOOT_DEVICE, - ), - 'PUT': ( - {}, - None, - ), - }, - '/v1/nodes/%s/management/inject_nmi' % NODE1['uuid']: - { - 'PUT': ( - {}, - None, - ), - }, - '/v1/nodes/%s/management/boot_device/supported' % NODE1['uuid']: - { - 'GET': ( - {}, - SUPPORTED_BOOT_DEVICE, - ), - }, - '/v1/nodes/%s/vendor_passthru/methods' % NODE1['uuid']: - { - 'GET': ( - {}, - NODE_VENDOR_PASSTHRU_METHOD, - ), - }, - '/v1/nodes/%s/vifs' % NODE1['uuid']: - { - 'GET': ( - {}, - VIFS, - ), - } -} - -fake_responses_pagination = { - '/v1/nodes': - { - 'GET': ( - {}, - {"nodes": [NODE1], - "next": "http://127.0.0.1:6385/v1/nodes/?limit=1"} - ), - }, - '/v1/nodes/?limit=1': - { - 'GET': ( - {}, - {"nodes": [NODE2]} - ), - }, - '/v1/nodes/?marker=%s' % NODE1['uuid']: - { - 'GET': ( - {}, - {"nodes": [NODE2]} - ), - }, - '/v1/nodes/%s/ports?limit=1' % NODE1['uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/ports?marker=%s' % (NODE1['uuid'], PORT['uuid']): - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/portgroups?limit=1' % NODE1['uuid']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/nodes/%s/portgroups?marker=%s' % (NODE1['uuid'], PORTGROUP['uuid']): - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/nodes/%s/volume/connectors?limit=1' % NODE1['uuid']: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR]}, - ), - }, - '/v1/nodes/%s/volume/connectors?marker=%s' % (NODE1['uuid'], - CONNECTOR['uuid']): - { - 'GET': ( - {}, - {"connectors": [CONNECTOR]}, - ), - }, - '/v1/nodes/%s/volume/targets?limit=1' % NODE1['uuid']: - { - 'GET': ( - {}, - {"targets": [TARGET]}, - ), - }, - '/v1/nodes/%s/volume/targets?marker=%s' % (NODE1['uuid'], TARGET['uuid']): - { - 'GET': ( - {}, - {"targets": [TARGET]}, - ), - }, -} - -fake_responses_sorting = { - '/v1/nodes/?sort_key=updated_at': - { - 'GET': ( - {}, - {"nodes": [NODE2, NODE1]} - ), - }, - '/v1/nodes/?sort_dir=desc': - { - 'GET': ( - {}, - {"nodes": [NODE2, NODE1]} - ), - }, - '/v1/nodes/%s/ports?sort_key=updated_at' % NODE1['uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/ports?sort_dir=desc' % NODE1['uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/nodes/%s/portgroups?sort_key=updated_at' % NODE1['uuid']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/nodes/%s/portgroups?sort_dir=desc' % NODE1['uuid']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/nodes/%s/volume/connectors?sort_key=updated_at' % NODE1['uuid']: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR]}, - ), - }, - '/v1/nodes/%s/volume/connectors?sort_dir=desc' % NODE1['uuid']: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR]}, - ), - }, - '/v1/nodes/%s/volume/targets?sort_key=updated_at' % NODE1['uuid']: - { - 'GET': ( - {}, - {"targets": [TARGET]}, - ), - }, - '/v1/nodes/%s/volume/targets?sort_dir=desc' % NODE1['uuid']: - { - 'GET': ( - {}, - {"targets": [TARGET]}, - ), - }, -} - - -class NodeManagerTest(testtools.TestCase): - - def setUp(self): - super(NodeManagerTest, self).setUp() - self.api = utils.FakeAPI(fake_responses) - self.mgr = node.NodeManager(self.api) - - def test_node_list(self): - nodes = self.mgr.list() - expect = [ - ('GET', '/v1/nodes', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(nodes)) - - def test_node_list_shows_name(self): - nodes = self.mgr.list() - self.assertIsNotNone(getattr(nodes[0], 'name')) - - def test_node_list_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - nodes = self.mgr.list(limit=1) - expect = [ - ('GET', '/v1/nodes/?limit=1', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - - def test_node_list_marker(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - nodes = self.mgr.list(marker=NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/?marker=%s' % NODE1['uuid'], {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - - def test_node_list_pagination_no_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - nodes = self.mgr.list(limit=0) - expect = [ - ('GET', '/v1/nodes', {}, None), - ('GET', '/v1/nodes/?limit=1', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(nodes)) - - def test_node_list_sort_key(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = node.NodeManager(self.api) - nodes = self.mgr.list(sort_key='updated_at') - expect = [ - ('GET', '/v1/nodes/?sort_key=updated_at', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(nodes)) - - def test_node_list_sort_dir(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = node.NodeManager(self.api) - nodes = self.mgr.list(sort_dir='desc') - expect = [ - ('GET', '/v1/nodes/?sort_dir=desc', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(nodes)) - - def test_node_list_associated(self): - nodes = self.mgr.list(associated=True) - expect = [ - ('GET', '/v1/nodes/?associated=True', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_unassociated(self): - nodes = self.mgr.list(associated=False) - expect = [ - ('GET', '/v1/nodes/?associated=False', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE1['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_unassociated_string(self): - nodes = self.mgr.list(associated="False") - expect = [ - ('GET', '/v1/nodes/?associated=False', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE1['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_maintenance(self): - nodes = self.mgr.list(maintenance=True) - expect = [ - ('GET', '/v1/nodes/?maintenance=True', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_maintenance_string(self): - nodes = self.mgr.list(maintenance="True") - expect = [ - ('GET', '/v1/nodes/?maintenance=True', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_provision_state(self): - nodes = self.mgr.list(provision_state="available") - expect = [ - ('GET', '/v1/nodes/?provision_state=available', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE1['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_provision_state_fail(self): - self.assertRaises(KeyError, self.mgr.list, - provision_state="test") - - def test_node_list_driver(self): - nodes = self.mgr.list(driver="fake") - expect = [ - ('GET', '/v1/nodes/?driver=fake', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE1['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_resource_class(self): - nodes = self.mgr.list(resource_class="foo") - expect = [ - ('GET', '/v1/nodes/?resource_class=foo', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE1['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_chassis(self): - ch2 = NODE2['chassis_uuid'] - nodes = self.mgr.list(chassis=ch2) - expect = [ - ('GET', '/v1/nodes/?chassis_uuid=%s' % ch2, {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_no_maintenance(self): - nodes = self.mgr.list(maintenance=False) - expect = [ - ('GET', '/v1/nodes/?maintenance=False', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE1['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_associated_and_maintenance(self): - nodes = self.mgr.list(associated=True, maintenance=True) - expect = [ - ('GET', '/v1/nodes/?associated=True&maintenance=True', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(nodes, HasLength(1)) - self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid')) - - def test_node_list_detail(self): - nodes = self.mgr.list(detail=True) - expect = [ - ('GET', '/v1/nodes/detail', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(nodes)) - self.assertEqual(nodes[0].extra, {}) - - def test_node_list_fields(self): - nodes = self.mgr.list(fields=['uuid', 'extra']) - expect = [ - ('GET', '/v1/nodes/?fields=uuid,extra', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(nodes)) - - def test_node_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, self.mgr.list, - detail=True, fields=['uuid', 'extra']) - - def test_node_show(self): - node = self.mgr.get(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NODE1['uuid'], node.uuid) - - def test_node_show_by_instance(self): - node = self.mgr.get_by_instance_uuid(NODE2['instance_uuid']) - expect = [ - ('GET', '/v1/nodes/detail?instance_uuid=%s' % - NODE2['instance_uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NODE2['uuid'], node.uuid) - - def test_node_show_by_name(self): - node = self.mgr.get(NODE1['name']) - expect = [ - ('GET', '/v1/nodes/%s' % NODE1['name'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NODE1['uuid'], node.uuid) - - def test_node_show_fields(self): - node = self.mgr.get(NODE1['uuid'], fields=['uuid', 'extra']) - expect = [ - ('GET', '/v1/nodes/%s?fields=uuid,extra' % - NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NODE1['uuid'], node.uuid) - - def test_create(self): - node = self.mgr.create(**CREATE_NODE) - expect = [ - ('POST', '/v1/nodes', {}, CREATE_NODE), - ] - self.assertEqual(expect, self.api.calls) - self.assertTrue(node) - - def test_create_with_uuid(self): - node = self.mgr.create(**CREATE_WITH_UUID) - expect = [ - ('POST', '/v1/nodes', {}, CREATE_WITH_UUID), - ] - self.assertEqual(expect, self.api.calls) - self.assertTrue(node) - - def test_delete(self): - node = self.mgr.delete(node_id=NODE1['uuid']) - expect = [ - ('DELETE', '/v1/nodes/%s' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(node) - - def test_update(self): - patch = {'op': 'replace', - 'value': NEW_DRIVER, - 'path': '/driver'} - node = self.mgr.update(node_id=NODE1['uuid'], patch=patch) - expect = [ - ('PATCH', '/v1/nodes/%s' % NODE1['uuid'], {}, patch), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NEW_DRIVER, node.driver) - - def test_node_port_list_with_uuid(self): - ports = self.mgr.list_ports(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/ports' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - self.assertEqual(PORT['uuid'], ports[0].uuid) - self.assertEqual(PORT['address'], ports[0].address) - - def test_node_port_list_with_name(self): - ports = self.mgr.list_ports(NODE1['name']) - expect = [ - ('GET', '/v1/nodes/%s/ports' % NODE1['name'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - self.assertEqual(PORT['uuid'], ports[0].uuid) - self.assertEqual(PORT['address'], ports[0].address) - - def test_node_port_list_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - ports = self.mgr.list_ports(NODE1['uuid'], limit=1) - expect = [ - ('GET', '/v1/nodes/%s/ports?limit=1' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - self.assertEqual(PORT['uuid'], ports[0].uuid) - self.assertEqual(PORT['address'], ports[0].address) - - def test_node_port_list_marker(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - ports = self.mgr.list_ports(NODE1['uuid'], marker=PORT['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/ports?marker=%s' % (NODE1['uuid'], - PORT['uuid']), {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - - def test_node_port_list_sort_key(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = node.NodeManager(self.api) - ports = self.mgr.list_ports(NODE1['uuid'], sort_key='updated_at') - expect = [ - ('GET', '/v1/nodes/%s/ports?sort_key=updated_at' % NODE1['uuid'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - self.assertEqual(PORT['uuid'], ports[0].uuid) - self.assertEqual(PORT['address'], ports[0].address) - - def test_node_port_list_sort_dir(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = node.NodeManager(self.api) - ports = self.mgr.list_ports(NODE1['uuid'], sort_dir='desc') - expect = [ - ('GET', '/v1/nodes/%s/ports?sort_dir=desc' % NODE1['uuid'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - self.assertEqual(PORT['uuid'], ports[0].uuid) - self.assertEqual(PORT['address'], ports[0].address) - - def test_node_port_list_detail_with_uuid(self): - ports = self.mgr.list_ports(NODE1['uuid'], detail=True) - expect = [ - ('GET', '/v1/nodes/%s/ports/detail' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - - def test_node_port_list_detail_with_name(self): - ports = self.mgr.list_ports(NODE1['name'], detail=True) - expect = [ - ('GET', '/v1/nodes/%s/ports/detail' % NODE1['name'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - - def test_node_port_list_fields(self): - ports = self.mgr.list_ports(NODE1['uuid'], fields=['uuid', 'address']) - expect = [ - ('GET', '/v1/nodes/%s/ports?fields=uuid,address' % - NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - - def test_node_port_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, self.mgr.list_ports, - NODE1['uuid'], detail=True, fields=['uuid', 'extra']) - - def _validate_node_volume_connector_list(self, expect, volume_connectors): - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(volume_connectors)) - self.assertIsInstance(volume_connectors[0], - volume_connector.VolumeConnector) - self.assertEqual(CONNECTOR['uuid'], volume_connectors[0].uuid) - self.assertEqual(CONNECTOR['type'], volume_connectors[0].type) - self.assertEqual(CONNECTOR['connector_id'], - volume_connectors[0].connector_id) - - def test_node_volume_connector_list(self): - volume_connectors = self.mgr.list_volume_connectors(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/volume/connectors' % NODE1['uuid'], - {}, None), - ] - self._validate_node_volume_connector_list(expect, volume_connectors) - - def test_node_volume_connector_list_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - volume_connectors = self.mgr.list_volume_connectors(NODE1['uuid'], - limit=1) - expect = [ - ('GET', '/v1/nodes/%s/volume/connectors?limit=1' % NODE1['uuid'], - {}, None), - ] - self._validate_node_volume_connector_list(expect, volume_connectors) - - def test_node_volume_connector_list_marker(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - volume_connectors = self.mgr.list_volume_connectors( - NODE1['uuid'], marker=CONNECTOR['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/volume/connectors?marker=%s' % ( - NODE1['uuid'], CONNECTOR['uuid']), {}, None), - ] - self._validate_node_volume_connector_list(expect, volume_connectors) - - def test_node_volume_connector_list_sort_key(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = node.NodeManager(self.api) - volume_connectors = self.mgr.list_volume_connectors( - NODE1['uuid'], sort_key='updated_at') - expect = [ - ('GET', '/v1/nodes/%s/volume/connectors?sort_key=updated_at' % - NODE1['uuid'], {}, None), - ] - self._validate_node_volume_connector_list(expect, volume_connectors) - - def test_node_volume_connector_list_sort_dir(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = node.NodeManager(self.api) - volume_connectors = self.mgr.list_volume_connectors(NODE1['uuid'], - sort_dir='desc') - expect = [ - ('GET', '/v1/nodes/%s/volume/connectors?sort_dir=desc' % - NODE1['uuid'], {}, None), - ] - self._validate_node_volume_connector_list(expect, volume_connectors) - - def test_node_volume_connector_list_detail(self): - volume_connectors = self.mgr.list_volume_connectors(NODE1['uuid'], - detail=True) - expect = [ - ('GET', - '/v1/nodes/%s/volume/connectors?detail=True' % NODE1['uuid'], - {}, None), - ] - self._validate_node_volume_connector_list(expect, volume_connectors) - - def test_node_volume_connector_list_fields(self): - volume_connectors = self.mgr.list_volume_connectors( - NODE1['uuid'], fields=['uuid', 'connector_id']) - expect = [ - ('GET', '/v1/nodes/%s/volume/connectors?fields=uuid,connector_id' % - NODE1['uuid'], {}, None), - ] - self._validate_node_volume_connector_list(expect, volume_connectors) - - def test_node_volume_connector_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, - self.mgr.list_volume_connectors, - NODE1['uuid'], detail=True, fields=['uuid', 'extra']) - - def _validate_node_volume_target_list(self, expect, volume_targets): - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(volume_targets)) - self.assertIsInstance(volume_targets[0], - volume_target.VolumeTarget) - self.assertEqual(TARGET['uuid'], volume_targets[0].uuid) - self.assertEqual(TARGET['volume_type'], volume_targets[0].volume_type) - self.assertEqual(TARGET['boot_index'], volume_targets[0].boot_index) - self.assertEqual(TARGET['volume_id'], volume_targets[0].volume_id) - self.assertEqual(TARGET['node_uuid'], volume_targets[0].node_uuid) - - def test_node_volume_target_list(self): - volume_targets = self.mgr.list_volume_targets(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/volume/targets' % NODE1['uuid'], - {}, None), - ] - self._validate_node_volume_target_list(expect, volume_targets) - - def test_node_volume_target_list_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - volume_targets = self.mgr.list_volume_targets(NODE1['uuid'], limit=1) - expect = [ - ('GET', '/v1/nodes/%s/volume/targets?limit=1' % NODE1['uuid'], - {}, None), - ] - self._validate_node_volume_target_list(expect, volume_targets) - - def test_node_volume_target_list_marker(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = node.NodeManager(self.api) - volume_targets = self.mgr.list_volume_targets( - NODE1['uuid'], marker=TARGET['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/volume/targets?marker=%s' % ( - NODE1['uuid'], TARGET['uuid']), {}, None), - ] - self._validate_node_volume_target_list(expect, volume_targets) - - def test_node_volume_target_list_sort_key(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = node.NodeManager(self.api) - volume_targets = self.mgr.list_volume_targets( - NODE1['uuid'], sort_key='updated_at') - expect = [ - ('GET', '/v1/nodes/%s/volume/targets?sort_key=updated_at' % - NODE1['uuid'], {}, None), - ] - self._validate_node_volume_target_list(expect, volume_targets) - - def test_node_volume_target_list_sort_dir(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = node.NodeManager(self.api) - volume_targets = self.mgr.list_volume_targets(NODE1['uuid'], - sort_dir='desc') - expect = [ - ('GET', '/v1/nodes/%s/volume/targets?sort_dir=desc' % - NODE1['uuid'], {}, None), - ] - self._validate_node_volume_target_list(expect, volume_targets) - - def test_node_volume_target_list_detail(self): - volume_targets = self.mgr.list_volume_targets(NODE1['uuid'], - detail=True) - expect = [ - ('GET', '/v1/nodes/%s/volume/targets?detail=True' % NODE1['uuid'], - {}, None), - ] - self._validate_node_volume_target_list(expect, volume_targets) - - def test_node_volume_target_list_fields(self): - volume_targets = self.mgr.list_volume_targets( - NODE1['uuid'], fields=['uuid', 'value']) - expect = [ - ('GET', '/v1/nodes/%s/volume/targets?fields=uuid,value' % - NODE1['uuid'], {}, None), - ] - self._validate_node_volume_target_list(expect, volume_targets) - - def test_node_volume_target_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, - self.mgr.list_volume_targets, - NODE1['uuid'], detail=True, fields=['uuid', 'extra']) - - def test_node_set_maintenance_true(self): - maintenance = self.mgr.set_maintenance(NODE1['uuid'], 'true', - maint_reason='reason') - body = {'reason': 'reason'} - expect = [ - ('PUT', '/v1/nodes/%s/maintenance' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(maintenance) - - def test_node_set_maintenance_false(self): - maintenance = self.mgr.set_maintenance(NODE1['uuid'], 'false') - expect = [ - ('DELETE', '/v1/nodes/%s/maintenance' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(maintenance) - - def test_node_set_maintenance_on(self): - maintenance = self.mgr.set_maintenance(NODE1['uuid'], 'on', - maint_reason='reason') - body = {'reason': 'reason'} - expect = [ - ('PUT', '/v1/nodes/%s/maintenance' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(maintenance) - - def test_node_set_maintenance_off(self): - maintenance = self.mgr.set_maintenance(NODE1['uuid'], 'off') - expect = [ - ('DELETE', '/v1/nodes/%s/maintenance' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(maintenance) - - def test_node_set_maintenance_bad(self): - self.assertRaises(exc.InvalidAttribute, self.mgr.set_maintenance, - NODE1['uuid'], 'bad') - - def test_node_set_maintenance_bool(self): - maintenance = self.mgr.set_maintenance(NODE1['uuid'], True, - maint_reason='reason') - body = {'reason': 'reason'} - expect = [ - ('PUT', '/v1/nodes/%s/maintenance' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(maintenance) - - def test_node_set_power_state(self): - power_state = self.mgr.set_power_state(NODE1['uuid'], "off") - body = {'target': 'power off'} - expect = [ - ('PUT', '/v1/nodes/%s/states/power' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual('power off', power_state.target_power_state) - - def test_node_set_power_timeout(self): - power_state = self.mgr.set_power_state(NODE1['uuid'], "off", timeout=2) - body = {'target': 'power off', 'timeout': 2} - expect = [ - ('PUT', '/v1/nodes/%s/states/power' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual('power off', power_state.target_power_state) - - def test_node_set_power_timeout_str(self): - power_state = self.mgr.set_power_state(NODE1['uuid'], "off", - timeout="2") - body = {'target': 'power off', 'timeout': 2} - expect = [ - ('PUT', '/v1/nodes/%s/states/power' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual('power off', power_state.target_power_state) - - def test_node_set_power_state_soft(self): - power_state = self.mgr.set_power_state(NODE1['uuid'], "off", soft=True) - body = {'target': 'soft power off'} - expect = [ - ('PUT', '/v1/nodes/%s/states/power' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual('power off', power_state.target_power_state) - - def test_node_set_power_state_soft_fail(self): - self.assertRaises(ValueError, - self.mgr.set_power_state, - NODE1['uuid'], 'on', soft=True) - - def test_node_set_power_state_on_timeout_fail(self): - self.assertRaises(ValueError, - self.mgr.set_power_state, - NODE1['uuid'], 'off', soft=False, timeout=0) - - def test_node_set_power_state_on_timeout_type_error(self): - self.assertRaises(ValueError, - self.mgr.set_power_state, - NODE1['uuid'], 'off', soft=False, timeout='a') - - def test_set_target_raid_config(self): - self.mgr.set_target_raid_config( - NODE1['uuid'], {'fake': 'config'}) - - expect = [('PUT', '/v1/nodes/%s/states/raid' % NODE1['uuid'], - {}, - {'fake': 'config'})] - self.assertEqual(expect, self.api.calls) - - def test_node_validate(self): - ifaces = self.mgr.validate(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/validate' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(DRIVER_IFACES['power'], ifaces.power) - self.assertEqual(DRIVER_IFACES['deploy'], ifaces.deploy) - self.assertEqual(DRIVER_IFACES['rescue'], ifaces.rescue) - self.assertEqual(DRIVER_IFACES['console'], ifaces.console) - - def test_node_set_provision_state(self): - target_state = 'active' - self.mgr.set_provision_state(NODE1['uuid'], target_state) - body = {'target': target_state} - expect = [ - ('PUT', '/v1/nodes/%s/states/provision' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - - def test_node_set_provision_state_with_configdrive(self): - target_state = 'active' - self.mgr.set_provision_state(NODE1['uuid'], target_state, - configdrive='foo') - body = {'target': target_state, 'configdrive': 'foo'} - expect = [ - ('PUT', '/v1/nodes/%s/states/provision' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - - def test_node_set_provision_state_with_configdrive_file(self): - target_state = 'active' - file_content = b'foo bar cat meow dog bark' - - with tempfile.NamedTemporaryFile() as f: - f.write(file_content) - f.flush() - self.mgr.set_provision_state(NODE1['uuid'], target_state, - configdrive=f.name) - - body = {'target': target_state, 'configdrive': file_content} - expect = [ - ('PUT', '/v1/nodes/%s/states/provision' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - - @mock.patch.object(common_utils, 'make_configdrive', autospec=True) - def test_node_set_provision_state_with_configdrive_dir(self, - mock_configdrive): - mock_configdrive.return_value = 'fake-configdrive' - target_state = 'active' - - with common_utils.tempdir() as dirname: - self.mgr.set_provision_state(NODE1['uuid'], target_state, - configdrive=dirname) - mock_configdrive.assert_called_once_with(dirname) - - body = {'target': target_state, 'configdrive': 'fake-configdrive'} - expect = [ - ('PUT', '/v1/nodes/%s/states/provision' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - - def test_node_set_provision_state_with_cleansteps(self): - cleansteps = [{"step": "upgrade", "interface": "deploy"}] - target_state = 'clean' - self.mgr.set_provision_state(NODE1['uuid'], target_state, - cleansteps=cleansteps) - body = {'target': target_state, 'clean_steps': cleansteps} - expect = [ - ('PUT', '/v1/nodes/%s/states/provision' % NODE1['uuid'], {}, body), - ] - self.assertEqual(expect, self.api.calls) - - def test_node_states(self): - states = self.mgr.states(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/states' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - expected_fields = ['last_error', 'power_state', 'provision_state', - 'target_power_state', 'target_provision_state'] - self.assertEqual(sorted(expected_fields), - sorted(states.to_dict().keys())) - - def test_node_set_console_mode(self): - global ENABLE - for enabled in ['true', True, 'False', False]: - self.api.calls = [] - ENABLE = enabled - self.mgr.set_console_mode(NODE1['uuid'], enabled) - body = {'enabled': enabled} - expect = [ - ('PUT', '/v1/nodes/%s/states/console' % NODE1['uuid'], {}, - body), - ] - self.assertEqual(expect, self.api.calls) - - def test_node_get_console(self): - info = self.mgr.get_console(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/states/console' % NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(CONSOLE_DATA_ENABLED, info) - - def test_node_get_console_disabled(self): - info = self.mgr.get_console(NODE2['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/states/console' % NODE2['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(CONSOLE_DATA_DISABLED, info) - - @mock.patch.object(node.NodeManager, 'update', autospec=True) - def test_vendor_passthru_update(self, update_mock): - # For now just mock the tests because vendor-passthru doesn't return - # anything to verify. - vendor_passthru_args = {'arg1': 'val1'} - kwargs = { - 'node_id': 'node_uuid', - 'method': 'method', - 'args': vendor_passthru_args - } - - final_path = 'node_uuid/vendor_passthru/method' - for http_method in ('POST', 'PUT', 'PATCH'): - kwargs['http_method'] = http_method - self.mgr.vendor_passthru(**kwargs) - update_mock.assert_called_once_with(mock.ANY, final_path, - vendor_passthru_args, - http_method=http_method) - update_mock.reset_mock() - - @mock.patch.object(node.NodeManager, 'get', autospec=True) - def test_vendor_passthru_get(self, get_mock): - kwargs = { - 'node_id': 'node_uuid', - 'method': 'method', - 'http_method': 'GET', - } - - final_path = 'node_uuid/vendor_passthru/method' - self.mgr.vendor_passthru(**kwargs) - get_mock.assert_called_once_with(mock.ANY, final_path) - - @mock.patch.object(node.NodeManager, 'delete', autospec=True) - def test_vendor_passthru_delete(self, delete_mock): - kwargs = { - 'node_id': 'node_uuid', - 'method': 'method', - 'http_method': 'DELETE', - } - - final_path = 'node_uuid/vendor_passthru/method' - self.mgr.vendor_passthru(**kwargs) - delete_mock.assert_called_once_with(mock.ANY, final_path) - - @mock.patch.object(node.NodeManager, 'delete', autospec=True) - def test_vendor_passthru_unknown_http_method(self, delete_mock): - kwargs = { - 'node_id': 'node_uuid', - 'method': 'method', - 'http_method': 'UNKNOWN', - } - self.assertRaises(exc.InvalidAttribute, self.mgr.vendor_passthru, - **kwargs) - - @mock.patch.object(node.NodeManager, '_list') - def test_vif_list(self, _list_mock): - kwargs = { - 'node_ident': NODE1['uuid'], - } - - final_path = '/v1/nodes/%s/vifs' % NODE1['uuid'] - self.mgr.vif_list(**kwargs) - _list_mock.assert_called_once_with(final_path, "vifs") - - @mock.patch.object(node.NodeManager, 'update') - def test_vif_attach(self, update_mock): - kwargs = { - 'node_ident': NODE1['uuid'], - 'vif_id': 'vif_id', - } - - final_path = '%s/vifs' % NODE1['uuid'] - self.mgr.vif_attach(**kwargs) - update_mock.assert_called_once_with(final_path, {'id': 'vif_id'}, - http_method="POST") - - @mock.patch.object(node.NodeManager, 'update') - def test_vif_attach_custom_fields(self, update_mock): - kwargs = { - 'node_ident': NODE1['uuid'], - 'vif_id': 'vif_id', - 'foo': 'bar', - } - - final_path = '%s/vifs' % NODE1['uuid'] - self.mgr.vif_attach(**kwargs) - update_mock.assert_called_once_with( - final_path, {'id': 'vif_id', 'foo': 'bar'}, - http_method="POST") - - @mock.patch.object(node.NodeManager, 'update') - def test_vif_attach_custom_fields_id(self, update_mock): - kwargs = { - 'node_ident': NODE1['uuid'], - 'vif_id': 'vif_id', - 'id': 'bar', - } - self.assertRaises( - exc.InvalidAttribute, - self.mgr.vif_attach, **kwargs) - - @mock.patch.object(node.NodeManager, 'delete') - def test_vif_detach(self, delete_mock): - kwargs = { - 'node_ident': NODE1['uuid'], - 'vif_id': 'vif_id', - } - - final_path = '%s/vifs/vif_id' % NODE1['uuid'] - self.mgr.vif_detach(**kwargs) - delete_mock.assert_called_once_with(final_path) - - def _test_node_set_boot_device(self, boot_device, persistent=False): - self.mgr.set_boot_device(NODE1['uuid'], boot_device, persistent) - body = {'boot_device': boot_device, 'persistent': persistent} - expect = [ - ('PUT', '/v1/nodes/%s/management/boot_device' % NODE1['uuid'], - {}, body), - ] - self.assertEqual(expect, self.api.calls) - - def test_node_set_boot_device(self): - self._test_node_set_boot_device('pxe') - - def test_node_set_boot_device_persistent(self): - self._test_node_set_boot_device('pxe', persistent=True) - - def test_node_get_boot_device(self): - boot_device = self.mgr.get_boot_device(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/management/boot_device' % NODE1['uuid'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(BOOT_DEVICE, boot_device) - - def test_node_inject_nmi(self): - self.mgr.inject_nmi(NODE1['uuid']) - expect = [ - ('PUT', '/v1/nodes/%s/management/inject_nmi' % NODE1['uuid'], - {}, {}), - ] - self.assertEqual(expect, self.api.calls) - - def test_node_get_supported_boot_devices(self): - boot_device = self.mgr.get_supported_boot_devices(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/management/boot_device/supported' % - NODE1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(SUPPORTED_BOOT_DEVICE, boot_device) - - def test_node_get_vendor_passthru_methods(self): - vendor_methods = self.mgr.get_vendor_passthru_methods(NODE1['uuid']) - expect = [ - ('GET', '/v1/nodes/%s/vendor_passthru/methods' % NODE1['uuid'], - {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NODE_VENDOR_PASSTHRU_METHOD, vendor_methods) - - def _fake_node_for_wait(self, state, error=None, target=None): - spec = ['provision_state', 'last_error', 'target_provision_state'] - return mock.Mock(provision_state=state, - last_error=error, - target_provision_state=target, - spec=spec) - - @mock.patch.object(time, 'sleep', autospec=True) - @mock.patch.object(node.NodeManager, 'get', autospec=True) - def test_wait_for_provision_state(self, mock_get, mock_sleep): - mock_get.side_effect = [ - self._fake_node_for_wait('deploying', target='active'), - self._fake_node_for_wait('deploying', target='active'), - self._fake_node_for_wait('active') - ] - - self.mgr.wait_for_provision_state('node', 'active') - - mock_get.assert_called_with(self.mgr, 'node') - self.assertEqual(3, mock_get.call_count) - mock_sleep.assert_called_with(node._DEFAULT_POLL_INTERVAL) - self.assertEqual(2, mock_sleep.call_count) - - @mock.patch.object(time, 'sleep', autospec=True) - @mock.patch.object(node.NodeManager, 'get', autospec=True) - def test_wait_for_provision_state_timeout(self, mock_get, mock_sleep): - mock_get.return_value = self._fake_node_for_wait( - 'deploying', target='active') - - self.assertRaises(exc.StateTransitionTimeout, - self.mgr.wait_for_provision_state, 'node', 'active', - timeout=0.001) - - @mock.patch.object(time, 'sleep', autospec=True) - @mock.patch.object(node.NodeManager, 'get', autospec=True) - def test_wait_for_provision_state_error(self, mock_get, mock_sleep): - mock_get.side_effect = [ - self._fake_node_for_wait('deploying', target='active'), - self._fake_node_for_wait('deploy failed', error='boom'), - ] - - self.assertRaisesRegex(exc.StateTransitionFailed, - 'boom', - self.mgr.wait_for_provision_state, - 'node', 'active') - - mock_get.assert_called_with(self.mgr, 'node') - self.assertEqual(2, mock_get.call_count) - mock_sleep.assert_called_with(node._DEFAULT_POLL_INTERVAL) - self.assertEqual(1, mock_sleep.call_count) - - @mock.patch.object(node.NodeManager, 'get', autospec=True) - def test_wait_for_provision_state_custom_delay(self, mock_get): - mock_get.side_effect = [ - self._fake_node_for_wait('deploying', target='active'), - self._fake_node_for_wait('active') - ] - - delay_mock = mock.Mock() - self.mgr.wait_for_provision_state('node', 'active', - poll_delay_function=delay_mock) - - mock_get.assert_called_with(self.mgr, 'node') - self.assertEqual(2, mock_get.call_count) - delay_mock.assert_called_with(node._DEFAULT_POLL_INTERVAL) - self.assertEqual(1, delay_mock.call_count) - - def test_wait_for_provision_state_wrong_input(self): - self.assertRaises(ValueError, self.mgr.wait_for_provision_state, - 'node', 'active', timeout='42') - self.assertRaises(ValueError, self.mgr.wait_for_provision_state, - 'node', 'active', timeout=-1) - self.assertRaises(TypeError, self.mgr.wait_for_provision_state, - 'node', 'active', poll_delay_function={}) - - @mock.patch.object(time, 'sleep', autospec=True) - @mock.patch.object(node.NodeManager, 'get', autospec=True) - def test_wait_for_provision_state_unexpected_stable_state( - self, mock_get, mock_sleep): - # This simulates aborted deployment - mock_get.side_effect = [ - self._fake_node_for_wait('deploying', target='active'), - self._fake_node_for_wait('available'), - ] - - self.assertRaisesRegex(exc.StateTransitionFailed, - 'available', - self.mgr.wait_for_provision_state, - 'node', 'active') - - mock_get.assert_called_with(self.mgr, 'node') - self.assertEqual(2, mock_get.call_count) - mock_sleep.assert_called_with(node._DEFAULT_POLL_INTERVAL) - self.assertEqual(1, mock_sleep.call_count) - - @mock.patch.object(time, 'sleep', autospec=True) - @mock.patch.object(node.NodeManager, 'get', autospec=True) - def test_wait_for_provision_state_unexpected_stable_state_allowed( - self, mock_get, mock_sleep): - mock_get.side_effect = [ - self._fake_node_for_wait('deploying', target='active'), - self._fake_node_for_wait('available'), - self._fake_node_for_wait('deploying', target='active'), - self._fake_node_for_wait('active'), - ] - - self.mgr.wait_for_provision_state('node', 'active', - fail_on_unexpected_state=False) - - mock_get.assert_called_with(self.mgr, 'node') - self.assertEqual(4, mock_get.call_count) - mock_sleep.assert_called_with(node._DEFAULT_POLL_INTERVAL) - self.assertEqual(3, mock_sleep.call_count) diff --git a/ironicclient/tests/unit/v1/test_node_shell.py b/ironicclient/tests/unit/v1/test_node_shell.py deleted file mode 100644 index b30eb20..0000000 --- a/ironicclient/tests/unit/v1/test_node_shell.py +++ /dev/null @@ -1,1314 +0,0 @@ -# Copyright 2013 IBM Corp -# -# 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 tempfile - -import mock - -from ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common import utils as commonutils -from ironicclient import exc -from ironicclient.tests.unit import utils -import ironicclient.v1.node_shell as n_shell -import ironicclient.v1.utils as v1_utils - - -class NodeShellTest(utils.BaseTestCase): - def test_node_show(self): - actual = {} - fake_print_dict = lambda data, *args, **kwargs: actual.update(data) - with mock.patch.object(cliutils, 'print_dict', fake_print_dict): - node = object() - n_shell._print_node_show(node) - exp = ['chassis_uuid', - 'clean_step', - 'created_at', - 'console_enabled', - 'driver', - 'driver_info', - 'driver_internal_info', - 'extra', - 'instance_info', - 'instance_uuid', - 'last_error', - 'maintenance', - 'maintenance_reason', - 'name', - 'boot_interface', - 'console_interface', - 'deploy_interface', - 'inspect_interface', - 'management_interface', - 'network_interface', - 'power_interface', - 'raid_interface', - 'storage_interface', - 'vendor_interface', - 'power_state', - 'properties', - 'provision_state', - 'provision_updated_at', - 'reservation', - 'resource_class', - 'target_power_state', - 'target_provision_state', - 'updated_at', - 'inspection_finished_at', - 'inspection_started_at', - 'uuid', - 'raid_config', - 'target_raid_config'] - act = actual.keys() - self.assertEqual(sorted(exp), sorted(act)) - - def test_do_node_delete(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = ['node_uuid'] - - n_shell.do_node_delete(client_mock, args) - client_mock.node.delete.assert_called_once_with('node_uuid') - - def test_do_node_delete_multiple(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = ['node_uuid1', 'node_uuid2'] - - n_shell.do_node_delete(client_mock, args) - client_mock.node.delete.assert_has_calls( - [mock.call('node_uuid1'), mock.call('node_uuid2')]) - - def test_do_node_delete_multiple_with_exception(self): - client_mock = mock.MagicMock() - client_mock.node.delete.side_effect = ( - [exceptions.ClientException, None]) - args = mock.MagicMock() - args.node = ['node_uuid1', 'node_uuid2'] - - self.assertRaises(exceptions.ClientException, n_shell.do_node_delete, - client_mock, args) - client_mock.node.delete.assert_has_calls( - [mock.call('node_uuid1'), mock.call('node_uuid2')]) - - def test_do_node_update(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.op = 'add' - args.attributes = [['arg1=val1', 'arg2=val2']] - args.json = False - - n_shell.do_node_update(client_mock, args) - patch = commonutils.args_array_to_patch(args.op, args.attributes[0]) - client_mock.node.update.assert_called_once_with('node_uuid', patch) - - def test_do_node_update_wrong_op(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.op = 'foo' - args.attributes = [['arg1=val1', 'arg2=val2']] - args.json = False - self.assertRaises(exceptions.CommandError, - n_shell.do_node_update, - client_mock, args) - self.assertFalse(client_mock.node.update.called) - - def test_do_node_create(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with() - - def test_do_node_create_with_driver(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.driver = 'driver' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - driver='driver') - - def test_do_node_create_with_chassis_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.chassis_uuid = 'chassis_uuid' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - chassis_uuid='chassis_uuid') - - def test_do_node_create_with_driver_info(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.driver_info = ['arg1=val1', 'arg2=val2'] - args.json = False - - n_shell.do_node_create(client_mock, args) - kwargs = {'driver_info': {'arg1': 'val1', 'arg2': 'val2'}} - client_mock.node.create.assert_called_once_with(**kwargs) - - def test_do_node_create_with_properties(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.properties = ['arg1=val1', 'arg2=val2'] - args.json = False - - n_shell.do_node_create(client_mock, args) - kwargs = {'properties': {'arg1': 'val1', 'arg2': 'val2'}} - client_mock.node.create.assert_called_once_with(**kwargs) - - def test_do_node_create_with_extra(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.driver = 'driver_name' - args.extra = ['arg1=val1', 'arg2=val2'] - args.json = False - - n_shell.do_node_create(client_mock, args) - kwargs = { - 'driver': 'driver_name', - 'extra': {'arg1': 'val1', 'arg2': 'val2'}, - } - client_mock.node.create.assert_called_once_with(**kwargs) - - def test_do_node_create_with_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.uuid = 'fef99cb8-a0d1-43df-b084-17b3b42b3cbd' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with(uuid=args.uuid) - - def test_do_node_create_with_name(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.name = 'node_name' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with(name=args.name) - - def test_do_node_create_with_boot_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.boot_interface = 'boot' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - boot_interface='boot') - - def test_do_node_create_with_console_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.console_interface = 'console' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - console_interface='console') - - def test_do_node_create_with_deploy_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.deploy_interface = 'deploy' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - deploy_interface='deploy') - - def test_do_node_create_with_inspect_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.inspect_interface = 'inspect' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - inspect_interface='inspect') - - def test_do_node_create_with_management_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.management_interface = 'management' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - management_interface='management') - - def test_do_node_create_with_network_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.network_interface = 'neutron' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - network_interface='neutron') - - def test_do_node_create_with_power_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.power_interface = 'power' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - power_interface='power') - - def test_do_node_create_with_raid_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.raid_interface = 'raid' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - raid_interface='raid') - - def test_do_node_create_with_storage_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.storage_interface = 'storage' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - storage_interface='storage') - - def test_do_node_create_with_vendor_interface(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.vendor_interface = 'vendor' - args.json = False - - n_shell.do_node_create(client_mock, args) - client_mock.node.create.assert_called_once_with( - vendor_interface='vendor') - - def test_do_node_show(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.instance_uuid = False - args.fields = None - args.json = False - - n_shell.do_node_show(client_mock, args) - client_mock.node.get.assert_called_once_with('node_uuid', fields=None) - # assert get_by_instance_uuid() wasn't called - self.assertFalse(client_mock.node.get_by_instance_uuid.called) - - def test_do_node_show_by_instance_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'instance_uuid' - args.instance_uuid = True - args.fields = None - args.json = False - - n_shell.do_node_show(client_mock, args) - client_mock.node.get_by_instance_uuid.assert_called_once_with( - 'instance_uuid', fields=None) - # assert get() wasn't called - self.assertFalse(client_mock.node.get.called) - - def test_do_node_show_by_space_node_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = ' ' - args.instance_uuid = False - args.json = False - self.assertRaises(exceptions.CommandError, - n_shell.do_node_show, - client_mock, args) - - def test_do_node_show_by_space_instance_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = ' ' - args.instance_uuid = True - args.json = False - self.assertRaises(exceptions.CommandError, - n_shell.do_node_show, - client_mock, args) - - def test_do_node_show_by_empty_node_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = '' - args.instance_uuid = False - args.json = False - self.assertRaises(exceptions.CommandError, - n_shell.do_node_show, - client_mock, args) - - def test_do_node_show_by_empty_instance_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = '' - args.instance_uuid = True - args.json = False - self.assertRaises(exceptions.CommandError, - n_shell.do_node_show, - client_mock, args) - - def test_do_node_show_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.instance_uuid = False - args.fields = [['uuid', 'power_state']] - args.json = False - n_shell.do_node_show(client_mock, args) - client_mock.node.get.assert_called_once_with( - 'node_uuid', fields=['uuid', 'power_state']) - - def test_do_node_show_invalid_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.instance_uuid = False - args.fields = [['foo', 'bar']] - args.json = False - self.assertRaises(exceptions.CommandError, - n_shell.do_node_show, client_mock, args) - - def test_do_node_set_maintenance_true(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.maintenance_mode = 'true' - args.reason = 'reason' - - n_shell.do_node_set_maintenance(client_mock, args) - client_mock.node.set_maintenance.assert_called_once_with( - 'node_uuid', True, maint_reason='reason') - - def test_do_node_set_maintenance_false(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.maintenance_mode = 'false' - # NOTE(jroll) None is the default. <3 mock. - args.reason = None - - n_shell.do_node_set_maintenance(client_mock, args) - client_mock.node.set_maintenance.assert_called_once_with( - 'node_uuid', False, maint_reason=None) - - def test_do_node_set_maintenance_bad(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.maintenance_mode = 'yuck' - # NOTE(jroll) None is the default. <3 mock. - args.reason = None - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_set_maintenance, client_mock, args) - self.assertFalse(client_mock.node.set_maintenance.called) - - def test_do_node_set_maintenance_false_with_reason_fails(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.maintenance_mode = 'false' - args.reason = 'reason' - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_set_maintenance, - client_mock, args) - - def test_do_node_set_maintenance_on(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.maintenance_mode = 'on' - args.reason = 'reason' - - n_shell.do_node_set_maintenance(client_mock, args) - client_mock.node.set_maintenance.assert_called_once_with( - 'node_uuid', True, maint_reason='reason') - - def test_do_node_set_maintenance_off(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.maintenance_mode = 'off' - # NOTE(jroll) None is the default. <3 mock. - args.reason = None - - n_shell.do_node_set_maintenance(client_mock, args) - client_mock.node.set_maintenance.assert_called_once_with( - 'node_uuid', False, maint_reason=None) - - def test_do_node_set_maintenance_off_with_reason_fails(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.maintenance_mode = 'off' - args.reason = 'reason' - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_set_maintenance, - client_mock, args) - - def _do_node_set_power_state_helper(self, power_state, - soft=False, timeout=None, error=False): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.power_state = power_state - args.soft = soft - args.power_timeout = timeout - - if error: - client_mock.node = mock.MagicMock() - client_mock.node.set_power_state = mock.MagicMock() - client_mock.node.set_power_state.side_effect = ValueError("fake") - self.assertRaises(exc.CommandError, - n_shell.do_node_set_power_state, - client_mock, args) - else: - n_shell.do_node_set_power_state(client_mock, args) - client_mock.node.set_power_state.assert_called_once_with( - 'node_uuid', power_state, soft, timeout=timeout) - - def test_do_node_set_power_state_on(self): - self._do_node_set_power_state_helper('on') - - def test_do_node_set_power_state_off(self): - self._do_node_set_power_state_helper('off') - - def test_do_node_set_power_state_reboot(self): - self._do_node_set_power_state_helper('reboot') - - def test_do_node_set_power_state_on_timeout(self): - self._do_node_set_power_state_helper('on', timeout=10) - - def test_do_node_set_power_state_on_timeout_fail(self): - self._do_node_set_power_state_helper('on', timeout=0, error=True) - - def test_do_node_set_power_state_off_timeout(self): - self._do_node_set_power_state_helper('off', timeout=10) - - def test_do_node_set_power_state_reboot_timeout(self): - self._do_node_set_power_state_helper('reboot', timeout=10) - - def test_do_node_set_power_state_soft_on_fail(self): - self._do_node_set_power_state_helper('on', soft=True, error=True) - - def test_do_node_set_power_state_soft_off(self): - self._do_node_set_power_state_helper('off', soft=True) - - def test_do_node_set_power_state_soft_reboot(self): - self._do_node_set_power_state_helper('reboot', soft=True) - - def test_do_node_set_power_state_soft_on_timeout_fail(self): - self._do_node_set_power_state_helper('on', soft=True, timeout=10, - error=True) - - def test_do_node_set_power_state_soft_off_timeout(self): - self._do_node_set_power_state_helper('off', soft=True, timeout=10) - - def test_do_node_set_power_state_soft_reboot_timeout(self): - self._do_node_set_power_state_helper('reboot', soft=True, timeout=10) - - def test_do_node_set_target_raid_config_file(self): - contents = '{"raid": "config"}' - - with tempfile.NamedTemporaryFile(mode='w') as f: - f.write(contents) - f.flush() - - node_manager_mock = mock.MagicMock(spec=['set_target_raid_config']) - client_mock = mock.MagicMock(spec=['node'], node=node_manager_mock) - args = mock.MagicMock() - args.node = 'node_uuid' - args.target_raid_config = f.name - - n_shell.do_node_set_target_raid_config(client_mock, args) - node_manager_mock.set_target_raid_config.assert_called_once_with( - 'node_uuid', json.loads(contents)) - - def test_do_node_set_target_raid_config_string(self): - node_manager_mock = mock.MagicMock(spec=['set_target_raid_config']) - client_mock = mock.MagicMock(spec=['node'], node=node_manager_mock) - target_raid_config_string = ( - '{"logical_disks": [{"size_gb": 100, "raid_level": "1"}]}') - expected_target_raid_config_string = json.loads( - target_raid_config_string) - - args = mock.MagicMock(node='node', - target_raid_config=target_raid_config_string) - n_shell.do_node_set_target_raid_config(client_mock, args) - - node_manager_mock.set_target_raid_config.assert_called_once_with( - 'node', expected_target_raid_config_string) - - @mock.patch.object(commonutils, 'get_from_stdin', autospec=True) - def test_set_target_raid_config_stdin(self, stdin_read_mock): - node_manager_mock = mock.MagicMock(spec=['set_target_raid_config']) - client_mock = mock.MagicMock(spec=['node'], node=node_manager_mock) - target_raid_config_string = ( - '{"logical_disks": [{"size_gb": 100, "raid_level": "1"}]}') - stdin_read_mock.return_value = target_raid_config_string - args_mock = mock.MagicMock(node='node', - target_raid_config='-') - expected_target_raid_config_string = json.loads( - target_raid_config_string) - n_shell.do_node_set_target_raid_config(client_mock, args_mock) - stdin_read_mock.assert_called_once_with('target_raid_config') - client_mock.node.set_target_raid_config.assert_called_once_with( - 'node', expected_target_raid_config_string) - - @mock.patch.object(commonutils, 'get_from_stdin', autospec=True) - def test_set_target_raid_config_stdin_exception(self, stdin_read_mock): - client_mock = mock.MagicMock() - stdin_read_mock.side_effect = exc.InvalidAttribute('bad') - args_mock = mock.MagicMock(node='node', - target_raid_config='-') - - self.assertRaises(exc.InvalidAttribute, - n_shell.do_node_set_target_raid_config, - client_mock, args_mock) - - stdin_read_mock.assert_called_once_with('target_raid_config') - self.assertFalse(client_mock.set_target_raid_config.called) - - def test_do_node_validate(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - - n_shell.do_node_validate(client_mock, args) - client_mock.node.validate.assert_called_once_with('node_uuid') - - def test_do_node_vendor_passthru_with_args(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.http_method = 'POST' - args.method = 'method' - args.arguments = [['arg1=val1', 'arg2=val2']] - - n_shell.do_node_vendor_passthru(client_mock, args) - client_mock.node.vendor_passthru.assert_called_once_with( - args.node, args.method, args={'arg1': 'val1', 'arg2': 'val2'}, - http_method=args.http_method) - - def test_do_node_vendor_passthru_without_args(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.http_method = 'POST' - args.method = 'method' - args.arguments = [[]] - - n_shell.do_node_vendor_passthru(client_mock, args) - client_mock.node.vendor_passthru.assert_called_once_with( - args.node, args.method, args={}, http_method=args.http_method) - - def test_do_node_set_provision_state_active(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'active' - args.config_drive = 'foo' - args.clean_steps = None - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'active', configdrive='foo', cleansteps=None) - self.assertFalse(client_mock.node.wait_for_provision_state.called) - - def test_do_node_set_provision_state_active_wait(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'active' - args.config_drive = 'foo' - args.clean_steps = None - args.wait_timeout = 0 - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'active', configdrive='foo', cleansteps=None) - client_mock.node.wait_for_provision_state.assert_called_once_with( - 'node_uuid', expected_state='active', timeout=0, - poll_interval=v1_utils._LONG_ACTION_POLL_INTERVAL) - - def test_do_node_set_provision_state_deleted(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'deleted' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'deleted', configdrive=None, cleansteps=None) - - def test_do_node_set_provision_state_rebuild(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'rebuild' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'rebuild', configdrive=None, cleansteps=None) - - def test_do_node_set_provision_state_not_active_fails(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'deleted' - args.config_drive = 'foo' - args.clean_steps = None - args.wait_timeout = None - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_set_provision_state, - client_mock, args) - self.assertFalse(client_mock.node.set_provision_state.called) - - def test_do_node_set_provision_state_inspect(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'inspect' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'inspect', configdrive=None, cleansteps=None) - - def test_do_node_set_provision_state_manage(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'manage' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'manage', configdrive=None, cleansteps=None) - - def test_do_node_set_provision_state_provide(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'provide' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'provide', configdrive=None, cleansteps=None) - - def test_do_node_set_provision_state_clean(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'clean' - args.config_drive = None - clean_steps = '[{"step": "upgrade", "interface": "deploy"}]' - args.clean_steps = clean_steps - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'clean', configdrive=None, - cleansteps=json.loads(clean_steps)) - - @mock.patch.object(commonutils, 'get_from_stdin', autospec=True) - def test_do_node_set_provision_state_clean_stdin(self, mock_stdin): - clean_steps = '[{"step": "upgrade", "interface": "deploy"}]' - mock_stdin.return_value = clean_steps - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'clean' - args.config_drive = None - args.clean_steps = '-' - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - mock_stdin.assert_called_once_with('clean steps') - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'clean', configdrive=None, - cleansteps=json.loads(clean_steps)) - - @mock.patch.object(commonutils, 'get_from_stdin', autospec=True) - def test_do_node_set_provision_state_clean_stdin_fails(self, mock_stdin): - mock_stdin.side_effect = exc.InvalidAttribute('bad') - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'clean' - args.config_drive = None - args.clean_steps = '-' - args.wait_timeout = None - - self.assertRaises(exc.InvalidAttribute, - n_shell.do_node_set_provision_state, - client_mock, args) - mock_stdin.assert_called_once_with('clean steps') - self.assertFalse(client_mock.node.set_provision_state.called) - - def test_do_node_set_provision_state_clean_file(self): - contents = '[{"step": "upgrade", "interface": "deploy"}]' - - with tempfile.NamedTemporaryFile(mode='w') as f: - f.write(contents) - f.flush() - - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'clean' - args.config_drive = None - args.clean_steps = f.name - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'clean', configdrive=None, - cleansteps=json.loads(contents)) - - def test_do_node_set_provision_state_clean_fails(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'clean' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = None - - # clean_steps isn't specified - self.assertRaisesRegex(exceptions.CommandError, - 'clean-steps.*must be specified', - n_shell.do_node_set_provision_state, - client_mock, args) - self.assertFalse(client_mock.node.set_provision_state.called) - - def test_do_node_set_provision_state_not_clean_fails(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'deleted' - args.config_drive = None - clean_steps = '[{"step": "upgrade", "interface": "deploy"}]' - args.clean_steps = clean_steps - args.wait_timeout = None - - # clean_steps specified but not cleaning - self.assertRaisesRegex(exceptions.CommandError, - 'clean-steps.*only valid', - n_shell.do_node_set_provision_state, - client_mock, args) - self.assertFalse(client_mock.node.set_provision_state.called) - - def test_do_node_set_provision_state_abort(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'abort' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = None - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'abort', configdrive=None, cleansteps=None) - - def test_do_node_set_provision_state_adopt(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'adopt' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = 0 - - n_shell.do_node_set_provision_state(client_mock, args) - client_mock.node.set_provision_state.assert_called_once_with( - 'node_uuid', 'adopt', cleansteps=None, configdrive=None) - - def test_do_node_set_provision_state_abort_no_wait(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.provision_state = 'abort' - args.config_drive = None - args.clean_steps = None - args.wait_timeout = 0 - - self.assertRaisesRegex(exceptions.CommandError, - "not supported for provision state 'abort'", - n_shell.do_node_set_provision_state, - client_mock, args) - self.assertFalse(client_mock.node.set_provision_state.called) - self.assertFalse(client_mock.node.wait_for_provision_state.called) - - def test_do_node_set_console_mode(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.enabled = 'true' - - n_shell.do_node_set_console_mode(client_mock, args) - client_mock.node.set_console_mode.assert_called_once_with( - 'node_uuid', True) - - def test_do_node_set_console_mode_bad(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.enabled = 'yuck' - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_set_console_mode, client_mock, args) - self.assertFalse(client_mock.node.set_console_mode.called) - - def test_do_node_set_boot_device(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.persistent = False - args.device = 'pxe' - - n_shell.do_node_set_boot_device(client_mock, args) - client_mock.node.set_boot_device.assert_called_once_with( - 'node_uuid', 'pxe', False) - - def test_do_node_set_boot_device_persistent(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.persistent = True - args.device = 'disk' - - n_shell.do_node_set_boot_device(client_mock, args) - client_mock.node.set_boot_device.assert_called_once_with( - 'node_uuid', 'disk', True) - - def test_do_node_get_boot_device(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.json = False - - n_shell.do_node_get_boot_device(client_mock, args) - client_mock.node.get_boot_device.assert_called_once_with('node_uuid') - - def test_do_node_inject_nmi(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - - n_shell.do_node_inject_nmi(client_mock, args) - client_mock.node.inject_nmi.assert_called_once_with('node_uuid') - - def test_do_node_get_supported_boot_devices(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.json = False - - n_shell.do_node_get_supported_boot_devices(client_mock, args) - client_mock.node.get_supported_boot_devices.assert_called_once_with( - 'node_uuid') - - def _get_client_mock_args(self, node=None, associated=None, - maintenance=None, marker=None, limit=None, - sort_dir=None, sort_key=None, detail=False, - fields=None, provision_state=None, driver=None, - json=False, resource_class=None): - args = mock.MagicMock() - args.node = node - args.associated = associated - args.maintenance = maintenance - args.provision_state = provision_state - args.marker = marker - args.limit = limit - args.sort_dir = sort_dir - args.sort_key = sort_key - args.detail = detail - args.fields = fields - args.driver = driver - args.json = json - args.resource_class = resource_class - - return args - - def test_do_node_list(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args() - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(detail=False) - - def test_do_node_list_detail(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(detail=True) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(detail=True) - - def test_do_node_list_provision_state(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(provision_state='wait call-back', - detail=False) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with( - provision_state='wait call-back', - detail=False) - - def test_do_node_list_detail_provision_state(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(provision_state='wait call-back', - detail=True) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with( - provision_state='wait call-back', - detail=True) - - def test_do_node_list_driver(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(driver='fake', - detail=False) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(driver='fake', - detail=False) - - def test_do_node_list_detail_driver(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(driver='fake', - detail=True) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(driver='fake', - detail=True) - - def test_do_node_list_resource_class(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(resource_class='foo', - detail=False) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(resource_class='foo', - detail=False) - - def test_do_node_list_detail_resource_class(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(resource_class='foo', - detail=True) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(resource_class='foo', - detail=True) - - def test_do_node_list_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='created_at', - detail=False) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(sort_key='created_at', - detail=False) - - def test_do_node_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='chassis_uuid', - detail=False) - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_list, - client_mock, args) - self.assertFalse(client_mock.node.list.called) - - def test_do_node_list_detail_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='created_at', - detail=True) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(sort_key='created_at', - detail=True) - - def test_do_node_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='chassis_uuid', - detail=True) - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_list, - client_mock, args) - self.assertFalse(client_mock.node.list.called) - - def test_do_node_list_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='desc', - detail=False) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(sort_dir='desc', - detail=False) - - def test_do_node_list_detail_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='asc', - detail=True) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(sort_dir='asc', - detail=True) - - def test_do_node_list_wrong_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='abc', - detail=False) - self.assertRaises(exceptions.CommandError, - n_shell.do_node_list, - client_mock, args) - self.assertFalse(client_mock.node.list.called) - - def test_do_node_list_maintenance(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(maintenance=True, - detail=False) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(maintenance=True, - detail=False) - - def test_do_node_list_detail_maintenance(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(maintenance=True, - detail=True) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(maintenance=True, - detail=True) - - def test_do_node_list_associated(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(associated=True, - detail=False) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(associated=True, - detail=False) - - def test_do_node_list_detail_associated(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(associated=True, - detail=True) - - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with(associated=True, - detail=True) - - def test_do_node_list_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['uuid', 'provision_state']]) - n_shell.do_node_list(client_mock, args) - client_mock.node.list.assert_called_once_with( - fields=['uuid', 'provision_state'], detail=False) - - def test_do_node_list_invalid_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['foo', 'bar']]) - self.assertRaises(exceptions.CommandError, - n_shell.do_node_list, client_mock, args) - - def test_do_node_show_states(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.json = False - - n_shell.do_node_show_states(client_mock, args) - client_mock.node.states.assert_called_once_with('node_uuid') - - def test_do_node_port_list(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock) - - n_shell.do_node_port_list(client_mock, args) - client_mock.node.list_ports.assert_called_once_with( - node_mock, detail=False) - - def test_do_node_port_list_detail(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, detail=True) - n_shell.do_node_port_list(client_mock, args) - client_mock.node.list_ports.assert_called_once_with( - node_mock, detail=True) - - def test_do_node_port_list_sort_key(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, - sort_key='created_at', - detail=False) - - n_shell.do_node_port_list(client_mock, args) - client_mock.node.list_ports.assert_called_once_with( - node_mock, sort_key='created_at', detail=False) - - def test_do_node_port_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, - sort_key='node_uuid', - detail=False) - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_port_list, - client_mock, args) - self.assertFalse(client_mock.node.list_ports.called) - - def test_do_node_port_list_detail_sort_key(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, - sort_key='created_at', - detail=True) - - n_shell.do_node_port_list(client_mock, args) - client_mock.node.list_ports.assert_called_once_with( - node_mock, sort_key='created_at', detail=True) - - def test_do_node_port_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, - sort_key='node_uuid', - detail=True) - - self.assertRaises(exceptions.CommandError, - n_shell.do_node_port_list, - client_mock, args) - self.assertFalse(client_mock.node.list_ports.called) - - def test_do_node_port_list_sort_dir(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, sort_dir='desc', - detail=False) - - n_shell.do_node_port_list(client_mock, args) - client_mock.node.list_ports.assert_called_once_with( - node_mock, sort_dir='desc', detail=False) - - def test_do_node_port_list_wrong_sort_dir(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, sort_dir='abc', - detail=False) - self.assertRaises(exceptions.CommandError, - n_shell.do_node_port_list, - client_mock, args) - self.assertFalse(client_mock.node.list_ports.called) - - def test_do_node_port_list_fields(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, - fields=[['uuid', 'address']]) - n_shell.do_node_port_list(client_mock, args) - client_mock.node.list_ports.assert_called_once_with( - node_mock, fields=['uuid', 'address'], detail=False) - - def test_do_node_port_list_invalid_fields(self): - client_mock = mock.MagicMock() - node_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(node=node_mock, - fields=[['foo', 'bar']]) - self.assertRaises(exceptions.CommandError, - n_shell.do_node_port_list, client_mock, args) - - def test_do_node_get_vendor_passthru_methods(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - n_shell.do_node_get_vendor_passthru_methods(client_mock, args) - client_mock.node.get_vendor_passthru_methods.assert_called_once_with( - 'node_uuid') - - def test_do_node_vif_list(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - n_shell.do_node_vif_list(client_mock, args) - client_mock.node.vif_list.assert_called_once_with( - 'node_uuid') - - def test_do_node_vif_attach(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.vif_id = 'aaa-aaa' - n_shell.do_node_vif_attach(client_mock, args) - client_mock.node.vif_attach.assert_called_once_with( - 'node_uuid', 'aaa-aaa') - - def test_do_node_vif_attach_custom_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.vif_id = 'aaa-aaa' - args.vif_info = ['aaa=bbb', 'ccc=ddd'] - n_shell.do_node_vif_attach(client_mock, args) - client_mock.node.vif_attach.assert_called_once_with( - 'node_uuid', 'aaa-aaa', aaa='bbb', ccc='ddd') - - def test_do_node_vif_detach(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node = 'node_uuid' - args.vif_id = 'aaa-aaa' - n_shell.do_node_vif_detach(client_mock, args) - client_mock.node.vif_detach.assert_called_once_with( - 'node_uuid', 'aaa-aaa') diff --git a/ironicclient/tests/unit/v1/test_port.py b/ironicclient/tests/unit/v1/test_port.py deleted file mode 100644 index 8817381..0000000 --- a/ironicclient/tests/unit/v1/test_port.py +++ /dev/null @@ -1,366 +0,0 @@ -# Copyright 2013 Red Hat, 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 copy - -import testtools -from testtools.matchers import HasLength - -from ironicclient import exc -from ironicclient.tests.unit import utils -import ironicclient.v1.port - -PORT = {'uuid': '11111111-2222-3333-4444-555555555555', - 'node_uuid': '55555555-4444-3333-2222-111111111111', - 'address': 'AA:BB:CC:DD:EE:FF', - 'pxe_enabled': True, - 'local_link_connection': {}, - 'portgroup_uuid': '55555555-4444-3333-2222-111111111111', - 'physical_network': 'physnet1', - 'extra': {}} - -PORT2 = {'uuid': '55555555-4444-3333-2222-111111111111', - 'node_uuid': '55555555-4444-3333-2222-111111111111', - 'address': 'AA:AA:AA:BB:BB:BB', - 'pxe_enabled': True, - 'local_link_connection': {}, - 'portgroup_uuid': '55555555-4444-3333-2222-111111111111', - 'physical_network': 'physnet2', - 'extra': {}} - -CREATE_PORT = copy.deepcopy(PORT) -del CREATE_PORT['uuid'] - -CREATE_PORT_WITH_UUID = copy.deepcopy(PORT) - -UPDATED_PORT = copy.deepcopy(PORT) -NEW_ADDR = 'AA:AA:AA:AA:AA:AA' -UPDATED_PORT['address'] = NEW_ADDR - -fake_responses = { - '/v1/ports': - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - 'POST': ( - {}, - CREATE_PORT, - ), - }, - '/v1/ports/detail': - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/ports/?fields=uuid,address': - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/ports/%s' % PORT['uuid']: - { - 'GET': ( - {}, - PORT, - ), - 'DELETE': ( - {}, - None, - ), - 'PATCH': ( - {}, - UPDATED_PORT, - ), - }, - '/v1/ports/%s?fields=uuid,address' % PORT['uuid']: - { - 'GET': ( - {}, - PORT, - ), - }, - '/v1/ports/detail?address=%s' % PORT['address']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/ports/?address=%s' % PORT['address']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/ports/?node=%s' % PORT['node_uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/ports/?portgroup=%s' % PORT['portgroup_uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, -} - -fake_responses_pagination = { - '/v1/ports': - { - 'GET': ( - {}, - {"ports": [PORT], - "next": "http://127.0.0.1:6385/v1/ports/?limit=1"} - ), - }, - '/v1/ports/?limit=1': - { - 'GET': ( - {}, - {"ports": [PORT2]} - ), - }, - '/v1/ports/?marker=%s' % PORT['uuid']: - { - 'GET': ( - {}, - {"ports": [PORT2]} - ), - }, -} - -fake_responses_sorting = { - '/v1/ports/?sort_key=updated_at': - { - 'GET': ( - {}, - {"ports": [PORT2, PORT]} - ), - }, - '/v1/ports/?sort_dir=desc': - { - 'GET': ( - {}, - {"ports": [PORT2, PORT]} - ), - }, -} - - -class PortManagerTest(testtools.TestCase): - - def setUp(self): - super(PortManagerTest, self).setUp() - self.api = utils.FakeAPI(fake_responses) - self.mgr = ironicclient.v1.port.PortManager(self.api) - - def test_ports_list(self): - ports = self.mgr.list() - expect = [ - ('GET', '/v1/ports', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - - def test_ports_list_by_address(self): - ports = self.mgr.list(address=PORT['address']) - expect = [ - ('GET', '/v1/ports/?address=%s' % PORT['address'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - - def test_ports_list_by_address_detail(self): - ports = self.mgr.list(address=PORT['address'], detail=True) - expect = [ - ('GET', '/v1/ports/detail?address=%s' % PORT['address'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - - def test_ports_list_by_node(self): - ports = self.mgr.list(node=PORT['node_uuid']) - expect = [ - ('GET', '/v1/ports/?node=%s' % PORT['node_uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - - def test_ports_list_by_portgroup(self): - ports = self.mgr.list(portgroup=PORT['portgroup_uuid']) - expect = [ - ('GET', '/v1/ports/?portgroup=%s' % PORT['portgroup_uuid'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - - def test_ports_list_detail(self): - ports = self.mgr.list(detail=True) - expect = [ - ('GET', '/v1/ports/detail', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - - def test_port_list_fields(self): - ports = self.mgr.list(fields=['uuid', 'address']) - expect = [ - ('GET', '/v1/ports/?fields=uuid,address', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - - def test_port_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, self.mgr.list, - detail=True, fields=['uuid', 'address']) - - def test_ports_list_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.port.PortManager(self.api) - ports = self.mgr.list(limit=1) - expect = [ - ('GET', '/v1/ports/?limit=1', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - - def test_ports_list_marker(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.port.PortManager(self.api) - ports = self.mgr.list(marker=PORT['uuid']) - expect = [ - ('GET', '/v1/ports/?marker=%s' % PORT['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(1)) - - def test_ports_list_pagination_no_limit(self): - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.port.PortManager(self.api) - ports = self.mgr.list(limit=0) - expect = [ - ('GET', '/v1/ports', {}, None), - ('GET', '/v1/ports/?limit=1', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertThat(ports, HasLength(2)) - - def test_ports_list_sort_key(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.port.PortManager(self.api) - ports = self.mgr.list(sort_key='updated_at') - expect = [ - ('GET', '/v1/ports/?sort_key=updated_at', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(ports)) - - def test_ports_list_sort_dir(self): - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.port.PortManager(self.api) - ports = self.mgr.list(sort_dir='desc') - expect = [ - ('GET', '/v1/ports/?sort_dir=desc', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(ports)) - - def test_ports_show(self): - port = self.mgr.get(PORT['uuid']) - expect = [ - ('GET', '/v1/ports/%s' % PORT['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(PORT['uuid'], port.uuid) - self.assertEqual(PORT['address'], port.address) - self.assertEqual(PORT['node_uuid'], port.node_uuid) - self.assertEqual(PORT['pxe_enabled'], port.pxe_enabled) - self.assertEqual(PORT['local_link_connection'], - port.local_link_connection) - self.assertEqual(PORT['portgroup_uuid'], port.portgroup_uuid) - self.assertEqual(PORT['physical_network'], port.physical_network) - - def test_ports_show_by_address(self): - port = self.mgr.get_by_address(PORT['address']) - expect = [ - ('GET', '/v1/ports/detail?address=%s' % PORT['address'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(PORT['uuid'], port.uuid) - self.assertEqual(PORT['address'], port.address) - self.assertEqual(PORT['node_uuid'], port.node_uuid) - self.assertEqual(PORT['pxe_enabled'], port.pxe_enabled) - self.assertEqual(PORT['local_link_connection'], - port.local_link_connection) - self.assertEqual(PORT['portgroup_uuid'], port.portgroup_uuid) - self.assertEqual(PORT['physical_network'], port.physical_network) - - def test_port_show_fields(self): - port = self.mgr.get(PORT['uuid'], fields=['uuid', 'address']) - expect = [ - ('GET', '/v1/ports/%s?fields=uuid,address' % - PORT['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(PORT['uuid'], port.uuid) - self.assertEqual(PORT['address'], port.address) - - def test_create(self): - port = self.mgr.create(**CREATE_PORT) - expect = [ - ('POST', '/v1/ports', {}, CREATE_PORT), - ] - self.assertEqual(expect, self.api.calls) - self.assertTrue(port) - - def test_create_with_uuid(self): - port = self.mgr.create(**CREATE_PORT_WITH_UUID) - expect = [ - ('POST', '/v1/ports', {}, CREATE_PORT_WITH_UUID), - ] - self.assertEqual(expect, self.api.calls) - self.assertTrue(port) - - def test_delete(self): - port = self.mgr.delete(port_id=PORT['uuid']) - expect = [ - ('DELETE', '/v1/ports/%s' % PORT['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(port) - - def test_update(self): - patch = {'op': 'replace', - 'value': NEW_ADDR, - 'path': '/address'} - port = self.mgr.update(port_id=PORT['uuid'], patch=patch) - expect = [ - ('PATCH', '/v1/ports/%s' % PORT['uuid'], {}, patch), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NEW_ADDR, port.address) diff --git a/ironicclient/tests/unit/v1/test_port_shell.py b/ironicclient/tests/unit/v1/test_port_shell.py deleted file mode 100644 index ce0e587..0000000 --- a/ironicclient/tests/unit/v1/test_port_shell.py +++ /dev/null @@ -1,329 +0,0 @@ -# Copyright 2013 IBM Corp -# -# 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 mock - -from oslo_utils import uuidutils - -from ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common import utils as commonutils -from ironicclient.tests.unit import utils -import ironicclient.v1.port_shell as p_shell - - -class PortShellTest(utils.BaseTestCase): - - def test_port_show(self): - actual = {} - fake_print_dict = lambda data, *args, **kwargs: actual.update(data) - with mock.patch.object(cliutils, 'print_dict', fake_print_dict): - port = object() - p_shell._print_port_show(port) - exp = ['address', 'created_at', 'extra', 'node_uuid', - 'physical_network', 'updated_at', 'uuid', 'pxe_enabled', - 'local_link_connection', 'internal_info', - 'portgroup_uuid'] - act = actual.keys() - self.assertEqual(sorted(exp), sorted(act)) - - def test_do_port_show(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = 'port_uuid' - args.address = False - args.fields = None - args.json = False - - p_shell.do_port_show(client_mock, args) - client_mock.port.get.assert_called_once_with('port_uuid', fields=None) - # assert get_by_address() wasn't called - self.assertFalse(client_mock.port.get_by_address.called) - - def test_do_port_show_space_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = ' ' - args.address = False - args.json = False - self.assertRaises(exceptions.CommandError, - p_shell.do_port_show, - client_mock, args) - - def test_do_port_show_empty_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = '' - args.address = False - args.json = False - self.assertRaises(exceptions.CommandError, - p_shell.do_port_show, - client_mock, args) - - def test_do_port_show_by_address(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = 'port_address' - args.address = True - args.fields = None - args.json = False - - p_shell.do_port_show(client_mock, args) - client_mock.port.get_by_address.assert_called_once_with('port_address', - fields=None) - # assert get() wasn't called - self.assertFalse(client_mock.port.get.called) - - def test_do_port_show_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = 'port_uuid' - args.address = False - args.fields = [['uuid', 'address']] - args.json = False - p_shell.do_port_show(client_mock, args) - client_mock.port.get.assert_called_once_with( - 'port_uuid', fields=['uuid', 'address']) - - def test_do_port_show_invalid_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = 'port_uuid' - args.address = False - args.fields = [['foo', 'bar']] - args.json = False - self.assertRaises(exceptions.CommandError, - p_shell.do_port_show, - client_mock, args) - - def test_do_port_update(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = 'port_uuid' - args.op = 'add' - args.attributes = [['arg1=val1', 'arg2=val2']] - args.json = False - - p_shell.do_port_update(client_mock, args) - patch = commonutils.args_array_to_patch(args.op, args.attributes[0]) - client_mock.port.update.assert_called_once_with('port_uuid', patch) - - def test_do_port_update_wrong_op(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = 'port_uuid' - args.op = 'foo' - args.attributes = [['arg1=val1', 'arg2=val2']] - args.json = False - self.assertRaises(exceptions.CommandError, - p_shell.do_port_update, - client_mock, args) - self.assertFalse(client_mock.port.update.called) - - def _get_client_mock_args(self, address=None, marker=None, limit=None, - sort_dir=None, sort_key=None, detail=False, - fields=None, json=False): - args = mock.MagicMock(spec=True) - args.address = address - args.marker = marker - args.limit = limit - args.sort_dir = sort_dir - args.sort_key = sort_key - args.detail = detail - args.fields = fields - args.json = json - - return args - - def test_do_port_list(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args() - - p_shell.do_port_list(client_mock, args) - client_mock.port.list.assert_called_once_with(detail=False) - - def test_do_port_list_detail(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(detail=True) - - p_shell.do_port_list(client_mock, args) - client_mock.port.list.assert_called_once_with(detail=True) - - def test_do_port_list_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='uuid', - detail=False) - - p_shell.do_port_list(client_mock, args) - client_mock.port.list.assert_called_once_with(sort_key='uuid', - detail=False) - - def test_do_port_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='node_uuid', detail=False) - - self.assertRaises(exceptions.CommandError, - p_shell.do_port_list, - client_mock, args) - self.assertFalse(client_mock.port.list.called) - - def test_do_port_list_detail_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='uuid', - detail=True) - - p_shell.do_port_list(client_mock, args) - client_mock.port.list.assert_called_once_with(sort_key='uuid', - detail=True) - - def test_do_port_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='node_uuid', - detail=True) - - self.assertRaises(exceptions.CommandError, - p_shell.do_port_list, - client_mock, args) - self.assertFalse(client_mock.port.list.called) - - def test_do_port_list_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['uuid', 'address']]) - - p_shell.do_port_list(client_mock, args) - client_mock.port.list.assert_called_once_with( - fields=['uuid', 'address'], detail=False) - - def test_do_port_list_invalid_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['foo', 'bar']]) - self.assertRaises(exceptions.CommandError, - p_shell.do_port_list, - client_mock, args) - - def test_do_port_list_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='desc', - detail=False) - - p_shell.do_port_list(client_mock, args) - client_mock.port.list.assert_called_once_with(sort_dir='desc', - detail=False) - - def test_do_port_list_detail_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='asc', - detail=True) - - p_shell.do_port_list(client_mock, args) - client_mock.port.list.assert_called_once_with(sort_dir='asc', - detail=True) - - def test_do_port_list_wrong_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='abc', - detail=False) - self.assertRaises(exceptions.CommandError, - p_shell.do_port_list, - client_mock, args) - self.assertFalse(client_mock.port.list.called) - - def test_do_port_create(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.json = False - p_shell.do_port_create(client_mock, args) - client_mock.port.create.assert_called_once_with() - - def test_do_port_create_with_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.uuid = uuidutils.generate_uuid() - args.json = False - - p_shell.do_port_create(client_mock, args) - client_mock.port.create.assert_called_once_with(uuid=args.uuid) - - def test_do_port_create_valid_fields_values(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.address = 'address' - args.node_uuid = 'uuid' - args.extra = ["key1=val1", "key2=val2"] - args.json = False - p_shell.do_port_create(client_mock, args) - client_mock.port.create.assert_called_once_with( - address='address', node_uuid='uuid', extra={'key1': 'val1', - 'key2': 'val2'}) - - def test_do_port_create_invalid_extra_fields_values(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.address = 'address' - args.node_uuid = 'uuid' - args.extra = ["foo"] - args.json = False - self.assertRaises(exceptions.CommandError, - p_shell.do_port_create, client_mock, args) - - def test_do_port_create_portgroup_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.address = 'address' - args.node_uuid = 'uuid' - args.portgroup_uuid = 'portgroup-uuid' - args.json = False - p_shell.do_port_create(client_mock, args) - client_mock.port.create.assert_called_once_with( - address='address', node_uuid='uuid', - portgroup_uuid='portgroup-uuid') - - def test_do_port_create_physical_network(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.address = 'address' - args.node_uuid = 'uuid' - args.physical_network = 'physnet1' - args.json = False - p_shell.do_port_create(client_mock, args) - client_mock.port.create.assert_called_once_with( - address='address', node_uuid='uuid', - physical_network='physnet1') - - def test_do_port_delete(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = ['port_uuid'] - p_shell.do_port_delete(client_mock, args) - client_mock.port.delete.assert_called_once_with('port_uuid') - - def test_do_port_delete_multiple(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.port = ['port_uuid', 'port_uuid2'] - p_shell.do_port_delete(client_mock, args) - client_mock.port.delete.assert_has_calls( - [mock.call('port_uuid'), mock.call('port_uuid2')]) - - def test_do_port_delete_multiple_with_exception(self): - client_mock = mock.MagicMock() - client_mock.port.delete.side_effect = ( - [exceptions.ClientException, None]) - args = mock.MagicMock() - args.port = ['port_uuid', 'port_uuid2'] - - self.assertRaises(exceptions.ClientException, - p_shell.do_port_delete, client_mock, args) - client_mock.port.delete.assert_has_calls( - [mock.call('port_uuid'), mock.call('port_uuid2')]) diff --git a/ironicclient/tests/unit/v1/test_portgroup.py b/ironicclient/tests/unit/v1/test_portgroup.py deleted file mode 100644 index 5ac1fd8..0000000 --- a/ironicclient/tests/unit/v1/test_portgroup.py +++ /dev/null @@ -1,440 +0,0 @@ -# Copyright 2016 Mirantis, 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 copy - -import mock -import testtools - -from ironicclient.common.apiclient import exceptions -from ironicclient.tests.unit import utils -import ironicclient.v1.portgroup -import ironicclient.v1.portgroup_shell as pg_shell - -PORTGROUP = {'uuid': '11111111-2222-3333-4444-555555555555', - 'name': 'Portgroup-name', - 'node_uuid': '66666666-7777-8888-9999-000000000000', - 'address': 'AA:BB:CC:DD:EE:FF', - 'extra': {}} - -PORTGROUP2 = {'uuid': '55555555-4444-3333-2222-111111111111', - 'name': 'Portgroup2-name', - 'node_uuid': '66666666-7777-8888-9999-000000000000', - 'address': 'AA:AA:AA:BB:BB:BB', - 'extra': {}} - -NODE1 = {'uuid': '66666666-7777-8888-9999-000000000000', - 'chassis_uuid': 'aaaaaaaa-1111-bbbb-2222-cccccccccccc', - 'maintenance': False, - 'provision_state': 'available', - 'driver': 'fake', - 'driver_info': {'user': 'foo', 'password': 'bar'}, - 'properties': {'num_cpu': 4}, - 'name': 'fake-node-1', - 'resource_class': 'foo', - 'extra': {}} - -PORT = {'uuid': '11111111-2222-3333-4444-555555555555', - 'portgroup_uuid': '11111111-2222-3333-4444-555555555555', - 'node_uuid': '66666666-7777-8888-9999-000000000000', - 'address': 'AA:AA:AA:AA:AA:AA', - 'extra': {}} - -CREATE_PORTGROUP = copy.deepcopy(PORTGROUP) -del CREATE_PORTGROUP['uuid'] - -UPDATED_PORTGROUP = copy.deepcopy(PORTGROUP) -NEW_ADDR = 'AA:AA:AA:AA:AA:AA' -UPDATED_PORTGROUP['address'] = NEW_ADDR - -fake_responses = { - '/v1/portgroups': - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP, PORTGROUP2]}, - ), - 'POST': ( - {}, - CREATE_PORTGROUP, - ), - }, - '/v1/portgroups/detail': - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP, PORTGROUP2]}, - ), - }, - '/v1/portgroups/%s' % PORTGROUP['uuid']: - { - 'GET': ( - {}, - PORTGROUP, - ), - 'DELETE': ( - {}, - None, - ), - 'PATCH': ( - {}, - UPDATED_PORTGROUP, - ), - }, - '/v1/portgroups/detail?address=%s' % PORTGROUP['address']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/portgroups/?address=%s' % PORTGROUP['address']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP]}, - ), - }, - '/v1/portgroups/%s/ports' % PORTGROUP['name']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, - '/v1/portgroups/%s/ports' % PORTGROUP['uuid']: - { - 'GET': ( - {}, - {"ports": [PORT]}, - ), - }, -} - -fake_responses_pagination = { - '/v1/portgroups': - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP], - "next": "http://127.0.0.1:6385/v1/portgroups/?limit=1"} - ), - }, - '/v1/portgroups/?limit=1': - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP2]} - ), - }, - '/v1/portgroups/?marker=%s' % PORTGROUP['uuid']: - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP2]} - ), - }, -} - -fake_responses_sorting = { - '/v1/portgroups/?sort_key=updated_at': - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP2, PORTGROUP]} - ), - }, - '/v1/portgroups/?sort_dir=desc': - { - 'GET': ( - {}, - {"portgroups": [PORTGROUP2, PORTGROUP]} - ), - }, -} - - -class PortgroupManagerTest(testtools.TestCase): - - def setUp(self): - super(PortgroupManagerTest, self).setUp() - self.api = utils.FakeAPI(fake_responses) - self.mgr = ironicclient.v1.portgroup.PortgroupManager(self.api) - - def test_portgroups_list(self): - portgroups = self.mgr.list() - expect = [ - ('GET', '/v1/portgroups', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(portgroups)) - - expected_resp = ({}, {"portgroups": [PORTGROUP, PORTGROUP2]},) - self.assertEqual(expected_resp, - self.api.responses['/v1/portgroups']['GET']) - - def test_portgroups_list_by_address(self): - portgroups = self.mgr.list(address=PORTGROUP['address']) - expect = [ - ('GET', '/v1/portgroups/?address=%s' % PORTGROUP['address'], {}, - None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(portgroups)) - - expected_resp = ({}, {"portgroups": [PORTGROUP, PORTGROUP2]},) - self.assertEqual(expected_resp, - self.api.responses['/v1/portgroups']['GET']) - - def test_portgroups_list_by_address_detail(self): - portgroups = self.mgr.list(address=PORTGROUP['address'], detail=True) - expect = [ - ('GET', '/v1/portgroups/detail?address=%s' % PORTGROUP['address'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(portgroups)) - - self.assertIn( - PORTGROUP, - self.api.responses['/v1/portgroups']['GET'][1]['portgroups']) - - def test_portgroups_list_detail(self): - portgroups = self.mgr.list(detail=True) - expect = [ - ('GET', '/v1/portgroups/detail', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(portgroups)) - - expected_resp = ({}, {"portgroups": [PORTGROUP, PORTGROUP2]},) - self.assertEqual(expected_resp, - self.api.responses['/v1/portgroups']['GET']) - - def test_portgroups_show(self): - portgroup = self.mgr.get(PORTGROUP['uuid']) - expect = [ - ('GET', '/v1/portgroups/%s' % PORTGROUP['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(PORTGROUP['uuid'], portgroup.uuid) - self.assertEqual(PORTGROUP['name'], portgroup.name) - self.assertEqual(PORTGROUP['node_uuid'], portgroup.node_uuid) - self.assertEqual(PORTGROUP['address'], portgroup.address) - - expected_resp = ({}, PORTGROUP,) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/%s' - % PORTGROUP['uuid']]['GET']) - - def test_portgroups_show_by_address(self): - portgroup = self.mgr.get_by_address(PORTGROUP['address']) - expect = [ - ('GET', '/v1/portgroups/detail?address=%s' % PORTGROUP['address'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(PORTGROUP['uuid'], portgroup.uuid) - self.assertEqual(PORTGROUP['name'], portgroup.name) - self.assertEqual(PORTGROUP['node_uuid'], portgroup.node_uuid) - self.assertEqual(PORTGROUP['address'], portgroup.address) - - expected_resp = ({}, {"portgroups": [PORTGROUP]},) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/detail?address=%s' - % PORTGROUP['address']]['GET']) - - def test_create(self): - portgroup = self.mgr.create(**CREATE_PORTGROUP) - expect = [ - ('POST', '/v1/portgroups', {}, CREATE_PORTGROUP), - ] - self.assertEqual(expect, self.api.calls) - self.assertTrue(portgroup) - - self.assertIn( - PORTGROUP, - self.api.responses['/v1/portgroups']['GET'][1]['portgroups']) - - def test_delete(self): - portgroup = self.mgr.delete(portgroup_id=PORTGROUP['uuid']) - expect = [ - ('DELETE', '/v1/portgroups/%s' % PORTGROUP['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(portgroup) - - expected_resp = ({}, PORTGROUP,) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/%s' - % PORTGROUP['uuid']]['GET']) - - def test_do_portgroup_delete_multiple_with_exception(self): - client_mock = mock.MagicMock() - client_mock.portgroup.delete.side_effect = ( - [exceptions.ClientException, None]) - args = mock.MagicMock() - args.portgroup = ['pg_uuid1', 'pg_uuid2'] - - self.assertRaises(exceptions.ClientException, - pg_shell.do_portgroup_delete, - client_mock, args) - client_mock.portgroup.delete.assert_has_calls( - [mock.call('pg_uuid1'), mock.call('pg_uuid2')]) - - expected_resp = ({}, PORTGROUP,) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/%s' - % PORTGROUP['uuid']]['GET']) - - def test_update(self): - patch = {'op': 'replace', - 'value': NEW_ADDR, - 'path': '/address'} - - portgroup = self.mgr.update(portgroup_id=PORTGROUP['uuid'], - patch=patch) - expect = [ - ('PATCH', '/v1/portgroups/%s' % PORTGROUP['uuid'], {}, patch), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(NEW_ADDR, portgroup.address) - - expected_resp = ({}, PORTGROUP,) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/%s' - % PORTGROUP['uuid']]['GET']) - - def test_portgroup_port_list_with_uuid(self): - ports = self.mgr.list_ports(PORTGROUP['uuid']) - expect = [ - ('GET', '/v1/portgroups/%s/ports' % PORTGROUP['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - self.assertEqual(PORT['uuid'], ports[0].uuid) - self.assertEqual(PORT['address'], ports[0].address) - - expected_resp = ({}, {"ports": [PORT]},) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/%s/ports' - % PORTGROUP['uuid']]['GET']) - - def test_portgroup_port_list_with_name(self): - ports = self.mgr.list_ports(PORTGROUP['name']) - expect = [ - ('GET', '/v1/portgroups/%s/ports' % PORTGROUP['name'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(ports)) - self.assertEqual(PORT['uuid'], ports[0].uuid) - self.assertEqual(PORT['address'], ports[0].address) - - expected_resp = ({}, {"ports": [PORT]},) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/%s/ports' - % PORTGROUP['name']]['GET']) - - -class PortgroupManagerPaginationTest(testtools.TestCase): - - def setUp(self): - super(PortgroupManagerPaginationTest, self).setUp() - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.portgroup.PortgroupManager(self.api) - - def test_portgroups_list_limit(self): - portgroups = self.mgr.list(limit=1) - expect = [ - ('GET', '/v1/portgroups/?limit=1', {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(portgroups)) - - expected_resp = ( - {}, {"next": "http://127.0.0.1:6385/v1/portgroups/?limit=1", - "portgroups": [PORTGROUP]},) - self.assertEqual(expected_resp, - self.api.responses['/v1/portgroups']['GET']) - - def test_portgroups_list_marker(self): - portgroups = self.mgr.list(marker=PORTGROUP['uuid']) - expect = [ - ('GET', '/v1/portgroups/?marker=%s' % PORTGROUP['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(1, len(portgroups)) - - expected_resp = ( - {}, {"next": "http://127.0.0.1:6385/v1/portgroups/?limit=1", - "portgroups": [PORTGROUP]},) - self.assertEqual(expected_resp, - self.api.responses['/v1/portgroups']['GET']) - - def test_portgroups_list_pagination_no_limit(self): - portgroups = self.mgr.list(limit=0) - expect = [ - ('GET', '/v1/portgroups', {}, None), - ('GET', '/v1/portgroups/?limit=1', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(portgroups)) - - expected_resp = ( - {}, {"next": "http://127.0.0.1:6385/v1/portgroups/?limit=1", - "portgroups": [PORTGROUP]},) - self.assertEqual(expected_resp, - self.api.responses['/v1/portgroups']['GET']) - - -class PortgroupManagerSortingTest(testtools.TestCase): - - def setUp(self): - super(PortgroupManagerSortingTest, self).setUp() - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.portgroup.PortgroupManager(self.api) - - def test_portgroups_list_sort_key(self): - portgroups = self.mgr.list(sort_key='updated_at') - expect = [ - ('GET', '/v1/portgroups/?sort_key=updated_at', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(portgroups)) - - expected_resp = ({}, {"portgroups": [PORTGROUP2, PORTGROUP]},) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/?sort_key=updated_at']['GET']) - - def test_portgroups_list_sort_dir(self): - portgroups = self.mgr.list(sort_dir='desc') - expect = [ - ('GET', '/v1/portgroups/?sort_dir=desc', {}, None) - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(2, len(portgroups)) - - expected_resp = ({}, {"portgroups": [PORTGROUP2, PORTGROUP]},) - self.assertEqual( - expected_resp, - self.api.responses['/v1/portgroups/?sort_dir=desc']['GET']) diff --git a/ironicclient/tests/unit/v1/test_portgroup_shell.py b/ironicclient/tests/unit/v1/test_portgroup_shell.py deleted file mode 100644 index 4a7a1a6..0000000 --- a/ironicclient/tests/unit/v1/test_portgroup_shell.py +++ /dev/null @@ -1,298 +0,0 @@ -# Copyright 2016 SAP Ltd. -# -# 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 mock - -from ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common import utils as commonutils -from ironicclient.tests.unit import utils -import ironicclient.v1.portgroup_shell as pg_shell - - -class PortgroupShellTest(utils.BaseTestCase): - - def test_portgroup_show(self): - actual = {} - fake_print_dict = lambda data, *args, **kwargs: actual.update(data) - with mock.patch.object(cliutils, 'print_dict', fake_print_dict): - portgroup = object() - pg_shell._print_portgroup_show(portgroup) - exp = ['address', 'created_at', 'extra', 'standalone_ports_supported', - 'node_uuid', 'updated_at', 'uuid', 'name', 'internal_info', - 'mode', 'properties'] - act = actual.keys() - self.assertEqual(sorted(exp), sorted(act)) - - def test_do_portgroup_show(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.portgroup = 'portgroup_uuid' - args.address = False - args.fields = None - args.json = False - - pg_shell.do_portgroup_show(client_mock, args) - client_mock.portgroup.get.assert_called_once_with('portgroup_uuid', - fields=None) - self.assertFalse(client_mock.portgroup.get_by_address.called) - - def test_do_portgroup_show_space_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.portgroup = ' ' - args.address = False - args.json = False - self.assertRaises(exceptions.CommandError, - pg_shell.do_portgroup_show, - client_mock, args) - - def test_do_portgroup_show_empty_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.portgroup = '' - args.address = False - args.json = False - self.assertRaises(exceptions.CommandError, - pg_shell.do_portgroup_show, - client_mock, args) - - def test_do_portgroup_show_by_address(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.portgroup = 'portgroup_address' - args.address = True - args.fields = None - args.json = False - - pg_shell.do_portgroup_show(client_mock, args) - client_mock.portgroup.get_by_address.assert_called_once_with( - 'portgroup_address', fields=None) - self.assertFalse(client_mock.portgroup.get.called) - - def test_do_portgroup_update(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.portgroup = 'portgroup_uuid' - args.op = 'add' - args.attributes = [['arg1=val1', 'arg2=val2']] - args.json = False - - pg_shell.do_portgroup_update(client_mock, args) - patch = commonutils.args_array_to_patch(args.op, args.attributes[0]) - client_mock.portgroup.update.assert_called_once_with('portgroup_uuid', - patch) - - def _get_client_mock_args(self, address=None, marker=None, limit=None, - sort_dir=None, sort_key=None, detail=False, - fields=None, node=None, json=False, - portgroup=None): - args = mock.MagicMock(spec=True) - args.address = address - args.node = node - args.marker = marker - args.limit = limit - args.sort_dir = sort_dir - args.sort_key = sort_key - args.detail = detail - args.fields = fields - args.json = json - args.portgroup = portgroup - - return args - - def test_do_portgroup_list(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args() - - pg_shell.do_portgroup_list(client_mock, args) - client_mock.portgroup.list.assert_called_once_with(detail=False) - - def test_do_portgroup_list_detail(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(detail=True) - - pg_shell.do_portgroup_list(client_mock, args) - client_mock.portgroup.list.assert_called_once_with(detail=True) - - def test_do_portgroup_list_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='uuid', - detail=False) - - pg_shell.do_portgroup_list(client_mock, args) - client_mock.portgroup.list.assert_called_once_with(sort_key='uuid', - detail=False) - - def test_do_portgroup_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='node_uuid', - detail=False) - - self.assertRaises(exceptions.CommandError, - pg_shell.do_portgroup_list, - client_mock, args) - self.assertFalse(client_mock.portgroup.list.called) - - def test_do_portgroup_list_detail_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='uuid', - detail=True) - - pg_shell.do_portgroup_list(client_mock, args) - client_mock.portgroup.list.assert_called_once_with(sort_key='uuid', - detail=True) - - def test_do_portgroup_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='node_uuid', - detail=True) - - self.assertRaises(exceptions.CommandError, - pg_shell.do_portgroup_list, - client_mock, args) - self.assertFalse(client_mock.portgroup.list.called) - - def test_do_portgroup_port_list(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock) - - pg_shell.do_portgroup_port_list(client_mock, args) - client_mock.portgroup.list_ports.assert_called_once_with( - pg_mock, detail=False) - - def test_do_portgroup_port_list_detail(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, detail=True) - - pg_shell.do_portgroup_port_list(client_mock, args) - client_mock.portgroup.list_ports.assert_called_once_with( - pg_mock, detail=True) - - def test_do_portgroup_port_list_sort_key(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, - sort_key='created_at') - - pg_shell.do_portgroup_port_list(client_mock, args) - client_mock.portgroup.list_ports.assert_called_once_with( - pg_mock, detail=False, sort_key='created_at') - - def test_do_portgroup_port_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, - sort_key='node_uuid') - self.assertRaises(exceptions.CommandError, - pg_shell.do_portgroup_port_list, - client_mock, args) - self.assertFalse(client_mock.portgroup.list_ports.called) - - def test_do_portgroup_port_list_detail_sort_key(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, - sort_key='created_at', - detail=True) - - pg_shell.do_portgroup_port_list(client_mock, args) - client_mock.portgroup.list_ports.assert_called_once_with( - pg_mock, detail=True, sort_key='created_at') - - def test_do_portgroup_port_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, - sort_key='node_uuid', - detail=True) - self.assertRaises(exceptions.CommandError, - pg_shell.do_portgroup_port_list, - client_mock, args) - self.assertFalse(client_mock.portgroup.list_ports.called) - - def test_do_portgroup_port_list_sort_dir(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, - sort_dir='desc') - pg_shell.do_portgroup_port_list(client_mock, args) - client_mock.portgroup.list_ports.assert_called_once_with( - pg_mock, detail=False, sort_dir='desc') - - def test_do_portgroup_port_list_wrong_sort_dir(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, - sort_dir='abc') - self.assertRaises(exceptions.CommandError, - pg_shell.do_portgroup_port_list, - client_mock, args) - self.assertFalse(client_mock.portgroup.list_ports.called) - - def test_do_portgroup_port_list_fields(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, - fields=[['uuid', 'address']]) - pg_shell.do_portgroup_port_list(client_mock, args) - client_mock.portgroup.list_ports.assert_called_once_with( - pg_mock, detail=False, fields=['uuid', 'address']) - - def test_do_portgroup_port_list_wrong_fields(self): - client_mock = mock.MagicMock() - pg_mock = mock.MagicMock(spec_set=[]) - args = self._get_client_mock_args(portgroup=pg_mock, - fields=[['foo', 'bar']]) - self.assertRaises(exceptions.CommandError, - pg_shell.do_portgroup_port_list, - client_mock, args) - self.assertFalse(client_mock.portgroup.list_ports.called) - - def test_do_portgroup_create(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.json = False - pg_shell.do_portgroup_create(client_mock, args) - client_mock.portgroup.create.assert_called_once_with() - - def test_do_portgroup_address(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.address = 'aa:bb:cc:dd:ee:ff' - args.mode = '802.3ad' - args.properties = ['xmit_hash_policy=layer3+4', 'miimon=100'] - args.json = False - pg_shell.do_portgroup_create(client_mock, args) - client_mock.portgroup.create.assert_called_once_with( - address='aa:bb:cc:dd:ee:ff', mode='802.3ad', - properties={'xmit_hash_policy': 'layer3+4', 'miimon': 100}) - - def test_do_portgroup_node_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.node_uuid = 'node-uuid' - args.json = False - pg_shell.do_portgroup_create(client_mock, args) - client_mock.portgroup.create.assert_called_once_with( - node_uuid='node-uuid') - - def test_do_portgroup_delete(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.portgroup = ['portgroup_uuid'] - pg_shell.do_portgroup_delete(client_mock, args) - client_mock.portgroup.delete.assert_called_once_with('portgroup_uuid') diff --git a/ironicclient/tests/unit/v1/test_resource_fields.py b/ironicclient/tests/unit/v1/test_resource_fields.py deleted file mode 100644 index 96044cf..0000000 --- a/ironicclient/tests/unit/v1/test_resource_fields.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (c) 2015 Intel Corporation -# -# 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 testtools - -from ironicclient.v1 import resource_fields - - -class ResourceTest(testtools.TestCase): - def setUp(self): - super(ResourceTest, self).setUp() - self._saved_ids = resource_fields.Resource.FIELDS - resource_fields.Resource.FIELDS = { - 'item1': 'ITEM1', - '2nd_item': 'A second item', - 'item_3': 'Third item', - } - - def tearDown(self): - super(ResourceTest, self).tearDown() - resource_fields.Resource.FIELDS = self._saved_ids - - def test_fields_single_value(self): - # Make sure single value is what we expect - foo = resource_fields.Resource(['item1']) - self.assertEqual(('item1',), foo.fields) - self.assertEqual(('ITEM1',), foo.labels) - self.assertEqual(('item1',), foo.sort_fields) - self.assertEqual(('ITEM1',), foo.sort_labels) - - def test_fields_multiple_value_order(self): - # Make sure order is maintained - foo = resource_fields.Resource(['2nd_item', 'item1']) - self.assertEqual(('2nd_item', 'item1'), foo.fields) - self.assertEqual(('A second item', 'ITEM1'), foo.labels) - self.assertEqual(('2nd_item', 'item1'), foo.sort_fields) - self.assertEqual(('A second item', 'ITEM1'), foo.sort_labels) - - def test_sort_excluded(self): - # Test excluding of fields for sort purposes - foo = resource_fields.Resource(['item_3', 'item1', '2nd_item'], - sort_excluded=['item1']) - self.assertEqual(('item_3', '2nd_item'), foo.sort_fields) - self.assertEqual(('Third item', 'A second item'), foo.sort_labels) - - def test_sort_excluded_unknown(self): - # Test sort_excluded value not in the field_ids - self.assertRaises( - ValueError, - resource_fields.Resource, - ['item_3', 'item1', '2nd_item'], - sort_excluded=['item1', 'foo']) - - def test_override_labels(self): - # Test overriding labels - foo = resource_fields.Resource(['item_3', 'item1', '2nd_item'], - override_labels={'item1': 'One'}) - self.assertEqual(('Third item', 'One', 'A second item'), foo.labels) - self.assertEqual(('Third item', 'One', 'A second item'), - foo.sort_labels) - - def test_override_labels_unknown(self): - # Test overriding labels with key not in field_ids - self.assertRaises( - ValueError, - resource_fields.Resource, - ['item_3', 'item1', '2nd_item'], - override_labels={'foo': 'One'}) - - def test_sort_excluded_override_labels(self): - # Test excluding of fields for sort purposes and overriding labels - foo = resource_fields.Resource(['item_3', 'item1', '2nd_item'], - sort_excluded=['item1'], - override_labels={'item_3': 'Three'}) - self.assertEqual(('Three', 'ITEM1', 'A second item'), foo.labels) - self.assertEqual(('item_3', '2nd_item'), foo.sort_fields) - self.assertEqual(('Three', 'A second item'), foo.sort_labels) - - def test_unknown_field_id(self): - self.assertRaises( - KeyError, - resource_fields.Resource, - ['item1', 'unknown_id']) diff --git a/ironicclient/tests/unit/v1/test_volume_connector.py b/ironicclient/tests/unit/v1/test_volume_connector.py deleted file mode 100644 index dd435c3..0000000 --- a/ironicclient/tests/unit/v1/test_volume_connector.py +++ /dev/null @@ -1,351 +0,0 @@ -# Copyright 2015 Hitachi Data Systems -# -# 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 copy - -import testtools - -from ironicclient import exc -from ironicclient.tests.unit import utils -import ironicclient.v1.port - -NODE_UUID = '55555555-4444-3333-2222-111111111111' -CONNECTOR1 = {'uuid': '11111111-2222-3333-4444-555555555555', - 'node_uuid': NODE_UUID, - 'type': 'iqn', - 'connector_id': 'iqn.2010-10.org.openstack:test', - 'extra': {}} - -CONNECTOR2 = {'uuid': '66666666-7777-8888-9999-000000000000', - 'node_uuid': NODE_UUID, - 'type': 'wwpn', - 'connector_id': '1234567890543216', - 'extra': {}} - -CREATE_CONNECTOR = copy.deepcopy(CONNECTOR1) -del CREATE_CONNECTOR['uuid'] - -CREATE_CONNECTOR_WITH_UUID = copy.deepcopy(CONNECTOR1) - -UPDATED_CONNECTOR = copy.deepcopy(CONNECTOR1) -NEW_CONNECTOR_ID = '1234567890123456' -UPDATED_CONNECTOR['connector_id'] = NEW_CONNECTOR_ID - -fake_responses = { - '/v1/volume/connectors': - { - 'GET': ( - {}, - {"connectors": [CONNECTOR1]}, - ), - 'POST': ( - {}, - CONNECTOR1, - ), - }, - '/v1/volume/connectors/?detail=True': - { - 'GET': ( - {}, - {"connectors": [CONNECTOR1]}, - ), - }, - '/v1/volume/connectors/?fields=uuid,connector_id': - { - 'GET': ( - {}, - {"connectors": [CONNECTOR1]}, - ), - }, - '/v1/volume/connectors/%s' % CONNECTOR1['uuid']: - { - 'GET': ( - {}, - CONNECTOR1, - ), - 'DELETE': ( - {}, - None, - ), - 'PATCH': ( - {}, - UPDATED_CONNECTOR, - ), - }, - '/v1/volume/connectors/%s?fields=uuid,connector_id' % CONNECTOR1['uuid']: - { - 'GET': ( - {}, - CONNECTOR1, - ), - }, - '/v1/volume/connectors/?detail=True&node=%s' % NODE_UUID: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR1]}, - ), - }, - '/v1/volume/connectors/?node=%s' % NODE_UUID: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR1]}, - ), - } -} - -fake_responses_pagination = { - '/v1/volume/connectors': - { - 'GET': ( - {}, - {"connectors": [CONNECTOR1], - "next": "http://127.0.0.1:6385/v1/volume/connectors/?marker=%s" % - CONNECTOR1['uuid']} - ), - }, - '/v1/volume/connectors/?limit=1': - { - 'GET': ( - {}, - {"connectors": [CONNECTOR1], - "next": "http://127.0.0.1:6385/v1/volume/connectors/?limit=1" - "&marker=%s" % CONNECTOR1['uuid']} - ), - }, - '/v1/volume/connectors/?limit=1&marker=%s' % CONNECTOR1['uuid']: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR2]} - ), - }, - '/v1/volume/connectors/?marker=%s' % CONNECTOR1['uuid']: - { - 'GET': ( - {}, - {"connectors": [CONNECTOR2]} - ), - }, -} - -fake_responses_sorting = { - '/v1/volume/connectors/?sort_key=updated_at': - { - 'GET': ( - {}, - {"connectors": [CONNECTOR2, CONNECTOR1]} - ), - }, - '/v1/volume/connectors/?sort_dir=desc': - { - 'GET': ( - {}, - {"connectors": [CONNECTOR2, CONNECTOR1]} - ), - }, -} - - -class VolumeConnectorManagerTestBase(testtools.TestCase): - - def _validate_obj(self, expect, obj): - self.assertEqual(expect['uuid'], obj.uuid) - self.assertEqual(expect['type'], obj.type) - self.assertEqual(expect['connector_id'], obj.connector_id) - self.assertEqual(expect['node_uuid'], obj.node_uuid) - - def _validate_list(self, expect_request, - expect_connectors, actual_connectors): - self.assertEqual(expect_request, self.api.calls) - self.assertEqual(len(expect_connectors), len(actual_connectors)) - for expect, obj in zip(expect_connectors, actual_connectors): - self._validate_obj(expect, obj) - - -class VolumeConnectorManagerTest(VolumeConnectorManagerTestBase): - - def setUp(self): - super(VolumeConnectorManagerTest, self).setUp() - self.api = utils.FakeAPI(fake_responses) - self.mgr = ironicclient.v1.volume_connector.VolumeConnectorManager( - self.api) - - def test_volume_connectors_list(self): - volume_connectors = self.mgr.list() - expect = [ - ('GET', '/v1/volume/connectors', {}, None), - ] - expect_connectors = [CONNECTOR1] - self._validate_list(expect, expect_connectors, volume_connectors) - - def test_volume_connectors_list_by_node(self): - volume_connectors = self.mgr.list(node=NODE_UUID) - expect = [ - ('GET', '/v1/volume/connectors/?node=%s' % NODE_UUID, {}, None), - ] - expect_connectors = [CONNECTOR1] - self._validate_list(expect, expect_connectors, volume_connectors) - - def test_volume_connectors_list_by_node_detail(self): - volume_connectors = self.mgr.list(node=NODE_UUID, detail=True) - expect = [ - ('GET', '/v1/volume/connectors/?detail=True&node=%s' % NODE_UUID, - {}, None), - ] - expect_connectors = [CONNECTOR1] - self._validate_list(expect, expect_connectors, volume_connectors) - - def test_volume_connectors_list_detail(self): - volume_connectors = self.mgr.list(detail=True) - expect = [ - ('GET', '/v1/volume/connectors/?detail=True', {}, None), - ] - expect_connectors = [CONNECTOR1] - self._validate_list(expect, expect_connectors, volume_connectors) - - def test_volume_connector_list_fields(self): - volume_connectors = self.mgr.list(fields=['uuid', 'connector_id']) - expect = [ - ('GET', - '/v1/volume/connectors/?fields=uuid,connector_id', - {}, - None), - ] - expect_connectors = [CONNECTOR1] - self._validate_list(expect, expect_connectors, volume_connectors) - - def test_volume_connector_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, self.mgr.list, - detail=True, fields=['uuid', 'connector_id']) - - def test_volume_connectors_show(self): - volume_connector = self.mgr.get(CONNECTOR1['uuid']) - expect = [ - ('GET', '/v1/volume/connectors/%s' % CONNECTOR1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self._validate_obj(CONNECTOR1, volume_connector) - - def test_volume_connector_show_fields(self): - volume_connector = self.mgr.get(CONNECTOR1['uuid'], - fields=['uuid', 'connector_id']) - expect = [ - ('GET', '/v1/volume/connectors/%s?fields=uuid,connector_id' % - CONNECTOR1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(CONNECTOR1['uuid'], volume_connector.uuid) - self.assertEqual(CONNECTOR1['connector_id'], - volume_connector.connector_id) - - def test_create(self): - volume_connector = self.mgr.create(**CREATE_CONNECTOR) - expect = [ - ('POST', '/v1/volume/connectors', {}, CREATE_CONNECTOR), - ] - self.assertEqual(expect, self.api.calls) - self._validate_obj(CONNECTOR1, volume_connector) - - def test_create_with_uuid(self): - volume_connector = self.mgr.create(**CREATE_CONNECTOR_WITH_UUID) - expect = [ - ('POST', '/v1/volume/connectors', {}, CREATE_CONNECTOR_WITH_UUID), - ] - self.assertEqual(expect, self.api.calls) - self._validate_obj(CREATE_CONNECTOR_WITH_UUID, volume_connector) - - def test_delete(self): - volume_connector = self.mgr.delete(CONNECTOR1['uuid']) - expect = [ - ('DELETE', '/v1/volume/connectors/%s' % CONNECTOR1['uuid'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(volume_connector) - - def test_update(self): - patch = {'op': 'replace', - 'connector_id': NEW_CONNECTOR_ID, - 'path': '/connector_id'} - volume_connector = self.mgr.update( - volume_connector_id=CONNECTOR1['uuid'], patch=patch) - expect = [ - ('PATCH', '/v1/volume/connectors/%s' % CONNECTOR1['uuid'], - {}, patch), - ] - self.assertEqual(expect, self.api.calls) - self._validate_obj(UPDATED_CONNECTOR, volume_connector) - - -class VolumeConnectorManagerPaginationTest(VolumeConnectorManagerTestBase): - - def setUp(self): - super(VolumeConnectorManagerPaginationTest, self).setUp() - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.volume_connector.VolumeConnectorManager( - self.api) - - def test_volume_connectors_list_limit(self): - volume_connectors = self.mgr.list(limit=1) - expect = [ - ('GET', '/v1/volume/connectors/?limit=1', {}, None), - ] - expect_connectors = [CONNECTOR1] - self._validate_list(expect, expect_connectors, volume_connectors) - - def test_volume_connectors_list_marker(self): - volume_connectors = self.mgr.list(marker=CONNECTOR1['uuid']) - expect = [ - ('GET', '/v1/volume/connectors/?marker=%s' % CONNECTOR1['uuid'], - {}, None), - ] - expect_connectors = [CONNECTOR2] - self._validate_list(expect, expect_connectors, volume_connectors) - - def test_volume_connectors_list_pagination_no_limit(self): - volume_connectors = self.mgr.list(limit=0) - expect = [ - ('GET', '/v1/volume/connectors', {}, None), - ('GET', '/v1/volume/connectors/?marker=%s' % CONNECTOR1['uuid'], - {}, None) - ] - expect_connectors = [CONNECTOR1, CONNECTOR2] - self._validate_list(expect, expect_connectors, volume_connectors) - - -class VolumeConnectorManagerSortingTest(VolumeConnectorManagerTestBase): - - def setUp(self): - super(VolumeConnectorManagerSortingTest, self).setUp() - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.volume_connector.VolumeConnectorManager( - self.api) - - def test_volume_connectors_list_sort_key(self): - volume_connectors = self.mgr.list(sort_key='updated_at') - expect = [ - ('GET', '/v1/volume/connectors/?sort_key=updated_at', {}, None) - ] - expect_connectors = [CONNECTOR2, CONNECTOR1] - self._validate_list(expect, expect_connectors, volume_connectors) - - def test_volume_connectors_list_sort_dir(self): - volume_connectors = self.mgr.list(sort_dir='desc') - expect = [ - ('GET', '/v1/volume/connectors/?sort_dir=desc', {}, None) - ] - expect_connectors = [CONNECTOR2, CONNECTOR1] - self._validate_list(expect, expect_connectors, volume_connectors) diff --git a/ironicclient/tests/unit/v1/test_volume_connector_shell.py b/ironicclient/tests/unit/v1/test_volume_connector_shell.py deleted file mode 100644 index 495cc77..0000000 --- a/ironicclient/tests/unit/v1/test_volume_connector_shell.py +++ /dev/null @@ -1,284 +0,0 @@ -# Copyright 2017 Hitachi Data Systems -# -# 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 mock - -from oslo_utils import uuidutils - -from ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common import utils as commonutils -from ironicclient.tests.unit import utils -import ironicclient.v1.volume_connector_shell as vc_shell - - -class Volume_ConnectorShellTest(utils.BaseTestCase): - - def test_volume_connector_show(self): - actual = {} - fake_print_dict = lambda data, *args, **kwargs: actual.update(data) - with mock.patch.object(cliutils, 'print_dict', fake_print_dict): - volume_connector = object() - vc_shell._print_volume_connector_show(volume_connector) - exp = ['created_at', 'extra', 'node_uuid', 'type', 'updated_at', - 'uuid', 'connector_id'] - act = actual.keys() - self.assertEqual(sorted(exp), sorted(act)) - - def test_do_volume_connector_show(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = 'volume_connector_uuid' - args.fields = None - args.json = False - - vc_shell.do_volume_connector_show(client_mock, args) - client_mock.volume_connector.get.assert_called_once_with( - 'volume_connector_uuid', fields=None) - - def test_do_volume_connector_show_space_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = ' ' - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_show, - client_mock, args) - - def test_do_volume_connector_show_empty_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = '' - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_show, - client_mock, args) - - def test_do_volume_connector_show_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = 'volume_connector_uuid' - args.fields = [['uuid', 'connector_id']] - args.json = False - vc_shell.do_volume_connector_show(client_mock, args) - client_mock.volume_connector.get.assert_called_once_with( - 'volume_connector_uuid', fields=['uuid', 'connector_id']) - - def test_do_volume_connector_show_invalid_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = 'volume_connector_uuid' - args.fields = [['foo', 'bar']] - args.json = False - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_show, - client_mock, args) - - def test_do_volume_connector_update(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = 'volume_connector_uuid' - args.op = 'add' - args.attributes = [['arg1=val1', 'arg2=val2']] - args.json = False - - vc_shell.do_volume_connector_update(client_mock, args) - patch = commonutils.args_array_to_patch(args.op, args.attributes[0]) - client_mock.volume_connector.update.assert_called_once_with( - 'volume_connector_uuid', patch) - - def test_do_volume_connector_update_wrong_op(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = 'volume_connector_uuid' - args.op = 'foo' - args.attributes = [['arg1=val1', 'arg2=val2']] - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_update, - client_mock, args) - self.assertFalse(client_mock.volume_connector.update.called) - - def _get_client_mock_args(self, node=None, marker=None, limit=None, - sort_dir=None, sort_key=None, detail=False, - fields=None, json=False): - args = mock.MagicMock(spec=True) - args.node = node - args.marker = marker - args.limit = limit - args.sort_dir = sort_dir - args.sort_key = sort_key - args.detail = detail - args.fields = fields - args.json = json - - return args - - def test_do_volume_connector_list(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args() - - vc_shell.do_volume_connector_list(client_mock, args) - client_mock.volume_connector.list.assert_called_once_with(detail=False) - - def test_do_volume_connector_list_detail(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(detail=True) - - vc_shell.do_volume_connector_list(client_mock, args) - client_mock.volume_connector.list.assert_called_once_with(detail=True) - - def test_do_volume_connector_list_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='uuid', - detail=False) - - vc_shell.do_volume_connector_list(client_mock, args) - client_mock.volume_connector.list.assert_called_once_with( - sort_key='uuid', detail=False) - - def test_do_volume_connector_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='node_uuid', detail=False) - - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_list, - client_mock, args) - self.assertFalse(client_mock.volume_connector.list.called) - - def test_do_volume_connector_list_detail_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='uuid', - detail=True) - - vc_shell.do_volume_connector_list(client_mock, args) - client_mock.volume_connector.list.assert_called_once_with( - sort_key='uuid', detail=True) - - def test_do_volume_connector_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='node_uuid', - detail=True) - - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_list, - client_mock, args) - self.assertFalse(client_mock.volume_connector.list.called) - - def test_do_volume_connector_list_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['uuid', 'connector_id']]) - - vc_shell.do_volume_connector_list(client_mock, args) - client_mock.volume_connector.list.assert_called_once_with( - fields=['uuid', 'connector_id'], detail=False) - - def test_do_volume_connector_list_invalid_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['foo', 'bar']]) - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_list, - client_mock, args) - - def test_do_volume_connector_list_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='desc', detail=False) - - vc_shell.do_volume_connector_list(client_mock, args) - client_mock.volume_connector.list.assert_called_once_with( - sort_dir='desc', detail=False) - - def test_do_volume_connector_list_detail_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='asc', detail=True) - - vc_shell.do_volume_connector_list(client_mock, args) - client_mock.volume_connector.list.assert_called_once_with( - sort_dir='asc', detail=True) - - def test_do_volume_connector_wrong_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='abc', detail=False) - - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_list, - client_mock, args) - self.assertFalse(client_mock.volume_connector.list.called) - - def test_do_volume_connector_create(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.json = False - vc_shell.do_volume_connector_create(client_mock, args) - client_mock.volume_connector.create.assert_called_once_with() - - def test_do_volume_connector_create_with_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.uuid = uuidutils.generate_uuid() - args.json = False - - vc_shell.do_volume_connector_create(client_mock, args) - client_mock.volume_connector.create.assert_called_once_with( - uuid=args.uuid) - - def test_do_volume_connector_create_valid_fields_values(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.type = 'type' - args.connector_id = 'connector_id' - args.node_uuid = 'uuid' - args.extra = ["key1=val1", "key2=val2"] - args.json = False - vc_shell.do_volume_connector_create(client_mock, args) - client_mock.volume_connector.create.assert_called_once_with( - type='type', connector_id='connector_id', node_uuid='uuid', - extra={'key1': 'val1', 'key2': 'val2'}) - - def test_do_volume_connector_create_invalid_extra_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.type = 'type' - args.connector_id = 'connector_id' - args.node_uuid = 'uuid' - args.extra = ["foo"] - args.json = False - self.assertRaises(exceptions.CommandError, - vc_shell.do_volume_connector_create, - client_mock, args) - - def test_do_volume_connector_delete(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = ['volume_connector_uuid'] - vc_shell.do_volume_connector_delete(client_mock, args) - client_mock.volume_connector.delete.assert_called_once_with( - 'volume_connector_uuid') - - def test_do_volume_connector_delete_multi(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = ['uuid1', 'uuid2'] - vc_shell.do_volume_connector_delete(client_mock, args) - self.assertEqual([mock.call('uuid1'), mock.call('uuid2')], - client_mock.volume_connector.delete.call_args_list) - - def test_do_volume_connector_delete_multi_error(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_connector = ['uuid1', 'uuid2'] - client_mock.volume_connector.delete.side_effect = [ - exceptions.ClientException('error'), None] - self.assertRaises(exceptions.ClientException, - vc_shell.do_volume_connector_delete, - client_mock, args) - self.assertEqual([mock.call('uuid1'), mock.call('uuid2')], - client_mock.volume_connector.delete.call_args_list) diff --git a/ironicclient/tests/unit/v1/test_volume_target.py b/ironicclient/tests/unit/v1/test_volume_target.py deleted file mode 100644 index dceb9f2..0000000 --- a/ironicclient/tests/unit/v1/test_volume_target.py +++ /dev/null @@ -1,349 +0,0 @@ -# Copyright 2016 Hitachi, Ltd. -# -# 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 copy - -import testtools - -from ironicclient import exc -from ironicclient.tests.unit import utils -import ironicclient.v1.port - -NODE_UUID = '55555555-4444-3333-2222-111111111111' -TARGET1 = {'uuid': '11111111-2222-3333-4444-555555555555', - 'node_uuid': NODE_UUID, - 'volume_type': 'iscsi', - 'properties': {'target_iqn': 'iqn.foo'}, - 'boot_index': 0, - 'volume_id': '12345678', - 'extra': {}} - -TARGET2 = {'uuid': '66666666-7777-8888-9999-000000000000', - 'node_uuid': NODE_UUID, - 'volume_type': 'fibre_channel', - 'properties': {'target_wwn': 'foobar'}, - 'boot_index': 1, - 'volume_id': '87654321', - 'extra': {}} - -CREATE_TARGET = copy.deepcopy(TARGET1) -del CREATE_TARGET['uuid'] - -CREATE_TARGET_WITH_UUID = copy.deepcopy(TARGET1) - -UPDATED_TARGET = copy.deepcopy(TARGET1) -NEW_VALUE = '100' -UPDATED_TARGET['boot_index'] = NEW_VALUE - -fake_responses = { - '/v1/volume/targets': - { - 'GET': ( - {}, - {"targets": [TARGET1]}, - ), - 'POST': ( - {}, - TARGET1 - ), - }, - '/v1/volume/targets/?detail=True': - { - 'GET': ( - {}, - {"targets": [TARGET1]}, - ), - }, - '/v1/volume/targets/?fields=uuid,boot_index': - { - 'GET': ( - {}, - {"targets": [TARGET1]}, - ), - }, - '/v1/volume/targets/%s' % TARGET1['uuid']: - { - 'GET': ( - {}, - TARGET1, - ), - 'DELETE': ( - {}, - None, - ), - 'PATCH': ( - {}, - UPDATED_TARGET, - ), - }, - '/v1/volume/targets/%s?fields=uuid,boot_index' % TARGET1['uuid']: - { - 'GET': ( - {}, - TARGET1, - ), - }, - '/v1/volume/targets/?detail=True&node=%s' % NODE_UUID: - { - 'GET': ( - {}, - {"targets": [TARGET1]}, - ), - }, - '/v1/volume/targets/?node=%s' % NODE_UUID: - { - 'GET': ( - {}, - {"targets": [TARGET1]}, - ), - } -} - -fake_responses_pagination = { - '/v1/volume/targets': - { - 'GET': ( - {}, - {"targets": [TARGET1], - "next": "http://127.0.0.1:6385/v1/volume/targets/?marker=%s" % - TARGET1['uuid']} - ), - }, - '/v1/volume/targets/?limit=1': - { - 'GET': ( - {}, - {"targets": [TARGET1], - "next": "http://127.0.0.1:6385/v1/volume/targets/?limit=1" - "&marker=%s" % TARGET1['uuid']} - ), - }, - '/v1/volume/targets/?limit=1&marker=%s' % TARGET1['uuid']: - { - 'GET': ( - {}, - {"targets": [TARGET2]} - ), - }, - '/v1/volume/targets/?marker=%s' % TARGET1['uuid']: - { - 'GET': ( - {}, - {"targets": [TARGET2]} - ), - }, -} - -fake_responses_sorting = { - '/v1/volume/targets/?sort_key=updated_at': - { - 'GET': ( - {}, - {"targets": [TARGET2, TARGET1]} - ), - }, - '/v1/volume/targets/?sort_dir=desc': - { - 'GET': ( - {}, - {"targets": [TARGET2, TARGET1]} - ), - }, -} - - -class VolumeTargetManagerTestBase(testtools.TestCase): - - def _validate_obj(self, expect, obj): - self.assertEqual(expect['uuid'], obj.uuid) - self.assertEqual(expect['volume_type'], obj.volume_type) - self.assertEqual(expect['boot_index'], obj.boot_index) - self.assertEqual(expect['volume_id'], obj.volume_id) - self.assertEqual(expect['node_uuid'], obj.node_uuid) - - def _validate_list(self, expect_request, - expect_targets, actual_targets): - self.assertEqual(expect_request, self.api.calls) - self.assertEqual(len(expect_targets), len(actual_targets)) - for expect, obj in zip(expect_targets, actual_targets): - self._validate_obj(expect, obj) - - -class VolumeTargetManagerTest(VolumeTargetManagerTestBase): - - def setUp(self): - super(VolumeTargetManagerTest, self).setUp() - self.api = utils.FakeAPI(fake_responses) - self.mgr = ironicclient.v1.volume_target.VolumeTargetManager(self.api) - - def test_volume_targets_list(self): - volume_targets = self.mgr.list() - expect = [ - ('GET', '/v1/volume/targets', {}, None), - ] - expect_targets = [TARGET1] - self._validate_list(expect, expect_targets, volume_targets) - - def test_volume_targets_list_by_node(self): - volume_targets = self.mgr.list(node=NODE_UUID) - expect = [ - ('GET', '/v1/volume/targets/?node=%s' % NODE_UUID, {}, None), - ] - expect_targets = [TARGET1] - self._validate_list(expect, expect_targets, volume_targets) - - def test_volume_targets_list_by_node_detail(self): - volume_targets = self.mgr.list(node=NODE_UUID, detail=True) - expect = [ - ('GET', '/v1/volume/targets/?detail=True&node=%s' % NODE_UUID, - {}, None), - ] - expect_targets = [TARGET1] - self._validate_list(expect, expect_targets, volume_targets) - - def test_volume_targets_list_detail(self): - volume_targets = self.mgr.list(detail=True) - expect = [ - ('GET', '/v1/volume/targets/?detail=True', {}, None), - ] - expect_targets = [TARGET1] - self._validate_list(expect, expect_targets, volume_targets) - - def test_volume_target_list_fields(self): - volume_targets = self.mgr.list(fields=['uuid', 'boot_index']) - expect = [ - ('GET', '/v1/volume/targets/?fields=uuid,boot_index', {}, None), - ] - expect_targets = [TARGET1] - self._validate_list(expect, expect_targets, volume_targets) - - def test_volume_target_list_detail_and_fields_fail(self): - self.assertRaises(exc.InvalidAttribute, self.mgr.list, - detail=True, fields=['uuid', 'boot_index']) - - def test_volume_targets_show(self): - volume_target = self.mgr.get(TARGET1['uuid']) - expect = [ - ('GET', '/v1/volume/targets/%s' % TARGET1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self._validate_obj(TARGET1, volume_target) - - def test_volume_target_show_fields(self): - volume_target = self.mgr.get(TARGET1['uuid'], - fields=['uuid', 'boot_index']) - expect = [ - ('GET', '/v1/volume/targets/%s?fields=uuid,boot_index' % - TARGET1['uuid'], {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertEqual(TARGET1['uuid'], volume_target.uuid) - self.assertEqual(TARGET1['boot_index'], volume_target.boot_index) - - def test_create(self): - volume_target = self.mgr.create(**CREATE_TARGET) - expect = [ - ('POST', '/v1/volume/targets', {}, CREATE_TARGET), - ] - self.assertEqual(expect, self.api.calls) - self._validate_obj(TARGET1, volume_target) - - def test_create_with_uuid(self): - volume_target = self.mgr.create(**CREATE_TARGET_WITH_UUID) - expect = [ - ('POST', '/v1/volume/targets', {}, CREATE_TARGET_WITH_UUID), - ] - self.assertEqual(expect, self.api.calls) - self._validate_obj(TARGET1, volume_target) - - def test_delete(self): - volume_target = self.mgr.delete(TARGET1['uuid']) - expect = [ - ('DELETE', '/v1/volume/targets/%s' % TARGET1['uuid'], - {}, None), - ] - self.assertEqual(expect, self.api.calls) - self.assertIsNone(volume_target) - - def test_update(self): - patch = {'op': 'replace', - 'value': NEW_VALUE, - 'path': '/boot_index'} - volume_target = self.mgr.update( - volume_target_id=TARGET1['uuid'], patch=patch) - expect = [ - ('PATCH', '/v1/volume/targets/%s' % TARGET1['uuid'], - {}, patch), - ] - self.assertEqual(expect, self.api.calls) - self._validate_obj(UPDATED_TARGET, volume_target) - - -class VolumeTargetManagerPaginationTest(VolumeTargetManagerTestBase): - - def setUp(self): - super(VolumeTargetManagerPaginationTest, self).setUp() - self.api = utils.FakeAPI(fake_responses_pagination) - self.mgr = ironicclient.v1.volume_target.VolumeTargetManager(self.api) - - def test_volume_targets_list_limit(self): - volume_targets = self.mgr.list(limit=1) - expect = [ - ('GET', '/v1/volume/targets/?limit=1', {}, None), - ] - expect_targets = [TARGET1] - self._validate_list(expect, expect_targets, volume_targets) - - def test_volume_targets_list_marker(self): - volume_targets = self.mgr.list(marker=TARGET1['uuid']) - expect = [ - ('GET', '/v1/volume/targets/?marker=%s' % TARGET1['uuid'], - {}, None), - ] - expect_targets = [TARGET2] - self._validate_list(expect, expect_targets, volume_targets) - - def test_volume_targets_list_pagination_no_limit(self): - volume_targets = self.mgr.list(limit=0) - expect = [ - ('GET', '/v1/volume/targets', {}, None), - ('GET', '/v1/volume/targets/?marker=%s' % TARGET1['uuid'], - {}, None) - ] - expect_targets = [TARGET1, TARGET2] - self._validate_list(expect, expect_targets, volume_targets) - - -class VolumeTargetManagerSortingTest(VolumeTargetManagerTestBase): - - def setUp(self): - super(VolumeTargetManagerSortingTest, self).setUp() - self.api = utils.FakeAPI(fake_responses_sorting) - self.mgr = ironicclient.v1.volume_target.VolumeTargetManager(self.api) - - def test_volume_targets_list_sort_key(self): - volume_targets = self.mgr.list(sort_key='updated_at') - expect = [ - ('GET', '/v1/volume/targets/?sort_key=updated_at', {}, None) - ] - expect_targets = [TARGET2, TARGET1] - self._validate_list(expect, expect_targets, volume_targets) - - def test_volume_targets_list_sort_dir(self): - volume_targets = self.mgr.list(sort_dir='desc') - expect = [ - ('GET', '/v1/volume/targets/?sort_dir=desc', {}, None) - ] - expect_targets = [TARGET2, TARGET1] - self._validate_list(expect, expect_targets, volume_targets) diff --git a/ironicclient/tests/unit/v1/test_volume_target_shell.py b/ironicclient/tests/unit/v1/test_volume_target_shell.py deleted file mode 100644 index 15e5c4b..0000000 --- a/ironicclient/tests/unit/v1/test_volume_target_shell.py +++ /dev/null @@ -1,288 +0,0 @@ -# Copyright 2017 Hitachi, Ltd. -# -# 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 mock - -from oslo_utils import uuidutils - -from ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common import utils as commonutils -from ironicclient.tests.unit import utils -import ironicclient.v1.volume_target_shell as vt_shell - - -class Volume_TargetShellTest(utils.BaseTestCase): - - def test_volume_target_show(self): - actual = {} - fake_print_dict = lambda data, *args, **kwargs: actual.update(data) - with mock.patch.object(cliutils, 'print_dict', fake_print_dict): - volume_target = object() - vt_shell._print_volume_target_show(volume_target) - exp = ['created_at', 'extra', 'node_uuid', 'volume_type', - 'updated_at', 'uuid', 'properties', 'boot_index', - 'volume_id'] - act = actual.keys() - self.assertEqual(sorted(exp), sorted(act)) - - def test_do_volume_target_show(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = 'volume_target_uuid' - args.fields = None - args.json = False - - vt_shell.do_volume_target_show(client_mock, args) - client_mock.volume_target.get.assert_called_once_with( - 'volume_target_uuid', fields=None) - - def test_do_volume_target_show_space_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = ' ' - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_show, - client_mock, args) - - def test_do_volume_target_show_empty_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = '' - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_show, - client_mock, args) - - def test_do_volume_target_show_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = 'volume_target_uuid' - args.fields = [['uuid', 'boot_index']] - args.json = False - vt_shell.do_volume_target_show(client_mock, args) - client_mock.volume_target.get.assert_called_once_with( - 'volume_target_uuid', fields=['uuid', 'boot_index']) - - def test_do_volume_target_show_invalid_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = 'volume_target_uuid' - args.fields = [['foo', 'bar']] - args.json = False - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_show, - client_mock, args) - - def test_do_volume_target_update(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = 'volume_target_uuid' - args.op = 'add' - args.attributes = [['arg1=val1', 'arg2=val2']] - args.json = False - - vt_shell.do_volume_target_update(client_mock, args) - patch = commonutils.args_array_to_patch(args.op, args.attributes[0]) - client_mock.volume_target.update.assert_called_once_with( - 'volume_target_uuid', patch) - - def test_do_volume_target_update_wrong_op(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = 'volume_target_uuid' - args.op = 'foo' - args.attributes = [['arg1=val1', 'arg2=val2']] - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_update, - client_mock, args) - self.assertFalse(client_mock.volume_target.update.called) - - def _get_client_mock_args(self, node=None, marker=None, limit=None, - sort_dir=None, sort_key=None, detail=False, - fields=None, json=False): - args = mock.MagicMock(spec=True) - args.node = node - args.marker = marker - args.limit = limit - args.sort_dir = sort_dir - args.sort_key = sort_key - args.detail = detail - args.fields = fields - args.json = json - - return args - - def test_do_volume_target_list(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args() - - vt_shell.do_volume_target_list(client_mock, args) - client_mock.volume_target.list.assert_called_once_with(detail=False) - - def test_do_volume_target_list_detail(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(detail=True) - - vt_shell.do_volume_target_list(client_mock, args) - client_mock.volume_target.list.assert_called_once_with(detail=True) - - def test_do_volume_target_list_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='uuid', detail=False) - - vt_shell.do_volume_target_list(client_mock, args) - client_mock.volume_target.list.assert_called_once_with( - sort_key='uuid', detail=False) - - def test_do_volume_target_list_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='node_uuid', detail=False) - - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_list, - client_mock, args) - self.assertFalse(client_mock.volume_target.list.called) - - def test_do_volume_target_list_detail_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='uuid', detail=True) - - vt_shell.do_volume_target_list(client_mock, args) - client_mock.volume_target.list.assert_called_once_with( - sort_key='uuid', detail=True) - - def test_do_volume_target_list_detail_wrong_sort_key(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_key='node_uuid', detail=True) - - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_list, - client_mock, args) - self.assertFalse(client_mock.volume_target.list.called) - - def test_do_volume_target_list_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['uuid', 'boot_index']]) - - vt_shell.do_volume_target_list(client_mock, args) - client_mock.volume_target.list.assert_called_once_with( - fields=['uuid', 'boot_index'], detail=False) - - def test_do_volume_target_list_invalid_fields(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(fields=[['foo', 'bar']]) - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_list, - client_mock, args) - - def test_do_volume_target_list_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='desc', detail=False) - - vt_shell.do_volume_target_list(client_mock, args) - client_mock.volume_target.list.assert_called_once_with( - sort_dir='desc', detail=False) - - def test_do_volume_target_list_detail_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='asc', detail=True) - - vt_shell.do_volume_target_list(client_mock, args) - client_mock.volume_target.list.assert_called_once_with( - sort_dir='asc', detail=True) - - def test_do_volume_target_wrong_sort_dir(self): - client_mock = mock.MagicMock() - args = self._get_client_mock_args(sort_dir='abc', detail=False) - - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_list, - client_mock, args) - self.assertFalse(client_mock.volume_target.list.called) - - def test_do_volume_target_create(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.json = False - vt_shell.do_volume_target_create(client_mock, args) - client_mock.volume_target.create.assert_called_once_with() - - def test_do_volume_target_create_with_uuid(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.uuid = uuidutils.generate_uuid() - args.json = False - - vt_shell.do_volume_target_create(client_mock, args) - client_mock.volume_target.create.assert_called_once_with( - uuid=args.uuid) - - def test_do_volume_target_create_valid_fields_values(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_type = 'volume_type' - args.properties = ["key1=val1", "key2=val2"] - args.boot_index = 100 - args.node_uuid = 'uuid' - args.volume_id = 'volume_id' - args.extra = ["key1=val1", "key2=val2"] - args.json = False - vt_shell.do_volume_target_create(client_mock, args) - client_mock.volume_target.create.assert_called_once_with( - volume_type='volume_type', - properties={'key1': 'val1', 'key2': 'val2'}, - boot_index=100, node_uuid='uuid', volume_id='volume_id', - extra={'key1': 'val1', 'key2': 'val2'}) - - def test_do_volume_target_create_invalid_extra_fields(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_type = 'volume_type' - args.properties = ["key1=val1", "key2=val2"] - args.boot_index = 100 - args.node_uuid = 'uuid' - args.volume_id = 'volume_id' - args.extra = ["foo"] - args.json = False - self.assertRaises(exceptions.CommandError, - vt_shell.do_volume_target_create, - client_mock, args) - - def test_do_volume_target_delete(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = ['volume_target_uuid'] - vt_shell.do_volume_target_delete(client_mock, args) - client_mock.volume_target.delete.assert_called_once_with( - 'volume_target_uuid') - - def test_do_volume_target_delete_multi(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = ['uuid1', 'uuid2'] - vt_shell.do_volume_target_delete(client_mock, args) - self.assertEqual([mock.call('uuid1'), mock.call('uuid2')], - client_mock.volume_target.delete.call_args_list) - - def test_do_volume_target_delete_multi_error(self): - client_mock = mock.MagicMock() - args = mock.MagicMock() - args.volume_target = ['uuid1', 'uuid2'] - client_mock.volume_target.delete.side_effect = [ - exceptions.ClientException('error'), None] - self.assertRaises(exceptions.ClientException, - vt_shell.do_volume_target_delete, - client_mock, args) - self.assertEqual([mock.call('uuid1'), mock.call('uuid2')], - client_mock.volume_target.delete.call_args_list) diff --git a/ironicclient/v1/__init__.py b/ironicclient/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ironicclient/v1/chassis.py b/ironicclient/v1/chassis.py deleted file mode 100644 index 84f7829..0000000 --- a/ironicclient/v1/chassis.py +++ /dev/null @@ -1,170 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2013 Red Hat, Inc -# -# 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 ironicclient.common import base -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc - - -class Chassis(base.Resource): - def __repr__(self): - return "" % self._info - - -class ChassisManager(base.CreateManager): - resource_class = Chassis - _resource_name = 'chassis' - _creation_attributes = ['description', 'extra', 'uuid'] - - def list(self, marker=None, limit=None, sort_key=None, - sort_dir=None, detail=False, fields=None): - """Retrieve a list of chassis. - - :param marker: Optional, the UUID of a chassis, eg the last - chassis from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of chassis to return. - 2) limit == 0, return the entire list of chassis. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about chassis. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: A list of chassis. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker, limit, sort_key, sort_dir, - fields) - - path = '' - if detail: - path += 'detail' - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "chassis") - else: - return self._list_pagination(self._path(path), "chassis", - limit=limit) - - def list_nodes(self, chassis_id, marker=None, limit=None, - sort_key=None, sort_dir=None, detail=False, fields=None, - associated=None, maintenance=None, provision_state=None): - """List all the nodes for a given chassis. - - :param chassis_id: The UUID of the chassis. - :param marker: Optional, the UUID of a node, eg the last - node from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of nodes to return. - 2) limit == 0, return the entire list of nodes. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about nodes. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :param associated: Optional. Either a Boolean or a string - representation of a Boolean that indicates whether - to return a list of associated (True or "True") or - unassociated (False or "False") nodes. - - :param maintenance: Optional. Either a Boolean or a string - representation of a Boolean that indicates whether - to return nodes in maintenance mode (True or - "True"), or not in maintenance mode (False or - "False"). - - :param provision_state: Optional. String value to get only nodes in - that provision state. - - :returns: A list of nodes. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker, limit, sort_key, sort_dir, - fields) - - if associated is not None: - filters.append('associated=%s' % associated) - if maintenance is not None: - filters.append('maintenance=%s' % maintenance) - if provision_state is not None: - filters.append('provision_state=%s' % provision_state) - - path = "%s/nodes" % chassis_id - if detail: - path += '/detail' - - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "nodes") - else: - return self._list_pagination(self._path(path), "nodes", - limit=limit) - - def get(self, chassis_id, fields=None): - return self._get(resource_id=chassis_id, fields=fields) - - def delete(self, chassis_id): - return self._delete(resource_id=chassis_id) - - def update(self, chassis_id, patch): - return self._update(resource_id=chassis_id, patch=patch) diff --git a/ironicclient/v1/chassis_shell.py b/ironicclient/v1/chassis_shell.py deleted file mode 100644 index bc5c852..0000000 --- a/ironicclient/v1/chassis_shell.py +++ /dev/null @@ -1,258 +0,0 @@ -# Copyright 2013 Red Hat, 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 ironicclient.common import cliutils -from ironicclient.common import utils -from ironicclient.v1 import resource_fields as res_fields - - -def _print_chassis_show(chassis, fields=None, json=False): - if fields is None: - fields = res_fields.CHASSIS_DETAILED_RESOURCE.fields - - data = dict([(f, getattr(chassis, f, '')) for f in fields]) - cliutils.print_dict(data, wrap=72, json_flag=json) - - -@cliutils.arg('chassis', metavar='', help="UUID of the chassis.") -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more chassis fields. Only these fields will be fetched from " - "the server.") -def do_chassis_show(cc, args): - """Show detailed information about a chassis.""" - utils.check_empty_arg(args.chassis, '') - fields = args.fields[0] if args.fields else None - utils.check_for_invalid_fields( - fields, res_fields.CHASSIS_DETAILED_RESOURCE.fields) - chassis = cc.chassis.get(args.chassis, fields=fields) - _print_chassis_show(chassis, fields=fields, json=args.json) - - -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help="Show detailed information about the chassis.") -@cliutils.arg( - '--limit', - metavar='', - type=int, - help='Maximum number of chassis to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Ironic API Service.') -@cliutils.arg( - '--marker', - metavar='', - help='Chassis UUID (for example, of the last chassis in the list ' - 'from a previous request). Returns the list of chassis ' - 'after this UUID.') -@cliutils.arg( - '--sort-key', - metavar='', - help='Chassis field that will be used for sorting.') -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help='Sort direction: "asc" (the default) or "desc".') -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more chassis fields. Only these fields will be fetched from " - "the server. Can not be used when '--detail' is specified.") -def do_chassis_list(cc, args): - """List the chassis.""" - if args.detail: - fields = res_fields.CHASSIS_DETAILED_RESOURCE.fields - field_labels = res_fields.CHASSIS_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], res_fields.CHASSIS_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.CHASSIS_RESOURCE.fields - field_labels = res_fields.CHASSIS_RESOURCE.labels - - sort_fields = res_fields.CHASSIS_DETAILED_RESOURCE.sort_fields - sort_field_labels = res_fields.CHASSIS_DETAILED_RESOURCE.sort_labels - - params = utils.common_params_for_list(args, sort_fields, - sort_field_labels) - - chassis = cc.chassis.list(**params) - cliutils.print_list(chassis, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg( - '-d', '--description', - metavar='', - help='Description of the chassis.') -@cliutils.arg( - '-e', '--extra', - metavar="", - action='append', - help="Record arbitrary key/value metadata. " - "Can be specified multiple times.") -@cliutils.arg( - '-u', '--uuid', - metavar='', - help="UUID of the chassis.") -def do_chassis_create(cc, args): - """Create a new chassis.""" - field_list = ['description', 'extra', 'uuid'] - fields = dict((k, v) for (k, v) in vars(args).items() - if k in field_list and not (v is None)) - fields = utils.args_array_to_dict(fields, 'extra') - chassis = cc.chassis.create(**fields) - - data = dict([(f, getattr(chassis, f, '')) for f in field_list]) - cliutils.print_dict(data, wrap=72, json_flag=args.json) - - -@cliutils.arg( - 'chassis', - metavar='', - nargs='+', - help="UUID of the chassis.") -def do_chassis_delete(cc, args): - """Delete a chassis.""" - for c in args.chassis: - cc.chassis.delete(c) - print('Deleted chassis %s' % c) - - -@cliutils.arg('chassis', metavar='', help="UUID of the chassis.") -@cliutils.arg( - 'op', - metavar='', - choices=['add', 'replace', 'remove'], - help="Operation: 'add', 'replace', or 'remove'.") -@cliutils.arg( - 'attributes', - metavar='', - nargs='+', - action='append', - default=[], - help="Attribute to add, replace, or remove. Can be specified " - "multiple times. For 'remove', only is necessary.") -def do_chassis_update(cc, args): - """Update information about a chassis.""" - patch = utils.args_array_to_patch(args.op, args.attributes[0]) - chassis = cc.chassis.update(args.chassis, patch) - _print_chassis_show(chassis, json=args.json) - - -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help="Show detailed information about the nodes.") -@cliutils.arg( - '--limit', - metavar='', - type=int, - help='Maximum number of nodes to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Ironic API Service.') -@cliutils.arg( - '--marker', - metavar='', - help='Node UUID (for example, of the last node in the list from ' - 'a previous request). Returns the list of nodes after this UUID.') -@cliutils.arg( - '--sort-key', - metavar='', - help='Node field that will be used for sorting.') -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help='Sort direction: "asc" (the default) or "desc".') -@cliutils.arg('chassis', metavar='', help="UUID of the chassis.") -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more node fields. Only these fields will be fetched from " - "the server. Can not be used when '--detail' is specified.") -@cliutils.arg( - '--maintenance', - metavar='', - help="List nodes in maintenance mode: 'true' or 'false'.") -@cliutils.arg( - '--associated', - metavar='', - help="List nodes by instance association: 'true' or 'false'.") -@cliutils.arg( - '--provision-state', - metavar='', - help="List nodes in specified provision state.") -def do_chassis_node_list(cc, args): - """List the nodes contained in a chassis.""" - params = {} - if args.associated is not None: - params['associated'] = utils.bool_argument_value("--associated", - args.associated) - if args.maintenance is not None: - params['maintenance'] = utils.bool_argument_value("--maintenance", - args.maintenance) - if args.provision_state is not None: - params['provision_state'] = args.provision_state - - if args.detail: - fields = res_fields.NODE_DETAILED_RESOURCE.fields - field_labels = res_fields.NODE_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], res_fields.NODE_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.NODE_RESOURCE.fields - field_labels = res_fields.NODE_RESOURCE.labels - - sort_fields = res_fields.NODE_DETAILED_RESOURCE.sort_fields - sort_field_labels = res_fields.NODE_DETAILED_RESOURCE.sort_labels - - params.update(utils.common_params_for_list(args, - sort_fields, - sort_field_labels)) - - nodes = cc.chassis.list_nodes(args.chassis, **params) - cliutils.print_list(nodes, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) diff --git a/ironicclient/v1/client.py b/ironicclient/v1/client.py deleted file mode 100644 index 377e97f..0000000 --- a/ironicclient/v1/client.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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 ironicclient.common import filecache -from ironicclient.common import http -from ironicclient.common.http import DEFAULT_VER -from ironicclient.common.i18n import _ -from ironicclient import exc -from ironicclient.v1 import chassis -from ironicclient.v1 import driver -from ironicclient.v1 import node -from ironicclient.v1 import port -from ironicclient.v1 import portgroup -from ironicclient.v1 import volume_connector -from ironicclient.v1 import volume_target - - -class Client(object): - """Client for the Ironic v1 API. - - :param string endpoint: A user-supplied endpoint URL for the ironic - service. - :param function token: Provides token for authentication. - :param integer timeout: Allows customization of the timeout for client - http requests. (optional) - """ - - def __init__(self, endpoint=None, *args, **kwargs): - """Initialize a new client for the Ironic v1 API.""" - if kwargs.get('os_ironic_api_version'): - kwargs['api_version_select_state'] = "user" - else: - if not endpoint: - raise exc.EndpointException( - _("Must provide 'endpoint' if os_ironic_api_version " - "isn't specified")) - - # If the user didn't specify a version, use a cached version if - # one has been stored - host, netport = http.get_server(endpoint) - saved_version = filecache.retrieve_data(host=host, port=netport) - if saved_version: - kwargs['api_version_select_state'] = "cached" - kwargs['os_ironic_api_version'] = saved_version - else: - kwargs['api_version_select_state'] = "default" - kwargs['os_ironic_api_version'] = DEFAULT_VER - - self.http_client = http._construct_http_client( - endpoint, *args, **kwargs) - - self.chassis = chassis.ChassisManager(self.http_client) - self.node = node.NodeManager(self.http_client) - self.port = port.PortManager(self.http_client) - self.volume_connector = volume_connector.VolumeConnectorManager( - self.http_client) - self.volume_target = volume_target.VolumeTargetManager( - self.http_client) - self.driver = driver.DriverManager(self.http_client) - self.portgroup = portgroup.PortgroupManager(self.http_client) diff --git a/ironicclient/v1/create_resources.py b/ironicclient/v1/create_resources.py deleted file mode 100644 index 746871b..0000000 --- a/ironicclient/v1/create_resources.py +++ /dev/null @@ -1,343 +0,0 @@ -# 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 functools -import json - -import jsonschema -import six -import yaml - -from ironicclient import exc - -_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Schema for ironic resources file", - "type": "object", - "properties": { - "chassis": { - "type": "array", - "items": { - "type": "object" - } - }, - "nodes": { - "type": "array", - "items": { - "type": "object" - } - } - }, - "additionalProperties": False -} - - -def create_resources(client, filenames): - """Create resources using their JSON or YAML descriptions. - - :param client: an instance of ironic client; - :param filenames: a list of filenames containing JSON or YAML resources - definitions. - :raises: ClientException if any operation during files processing/resource - creation fails. - """ - errors = [] - resources = [] - for resource_file in filenames: - try: - resource = load_from_file(resource_file) - jsonschema.validate(resource, _CREATE_SCHEMA) - resources.append(resource) - except (exc.ClientException, jsonschema.ValidationError) as e: - errors.append(e) - if errors: - raise exc.ClientException('While validating the resources file(s), the' - ' following error(s) were encountered:\n%s' % - '\n'.join(six.text_type(e) for e in errors)) - for r in resources: - errors.extend(create_chassis(client, r.get('chassis', []))) - errors.extend(create_nodes(client, r.get('nodes', []))) - if errors: - raise exc.ClientException('During resources creation, the following ' - 'error(s) were encountered:\n%s' % - '\n'.join(six.text_type(e) for e in errors)) - - -def load_from_file(filename): - """Deserialize JSON or YAML from file. - - :param filename: name of the file containing JSON or YAML. - :returns: a dictionary deserialized from JSON or YAML. - :raises: ClientException if the file can not be loaded or if its contents - is not a valid JSON or YAML, or if the file extension is not supported. - """ - try: - with open(filename) as f: - if filename.endswith('.yaml'): - return yaml.safe_load(f) - elif filename.endswith('.json'): - return json.load(f) - else: - # The file is neither .json, nor .yaml, raise an exception - raise exc.ClientException( - 'Cannot process file "%(file)s" - it must have .json or ' - '.yaml extension.' % {'file': filename}) - except IOError as e: - raise exc.ClientException('Cannot read file "%(file)s" due to ' - 'error: %(err)s' % - {'err': e, 'file': filename}) - except (ValueError, yaml.YAMLError) as e: - # json.load raises only ValueError - raise exc.ClientException('File "%(file)s" is invalid due to error: ' - '%(err)s' % {'err': e, 'file': filename}) - - -def create_single_handler(resource_type): - """Catch errors of the creation of a single resource. - - This decorator appends an error (which is an instance of some client - exception class) to the return value of the create_method, changing the - return value from just UUID to (UUID, error), and does some exception - handling. - - :param resource_type: string value, the type of the resource being created, - e.g. 'node', used purely for exception messages. - """ - - def outer_wrapper(create_method): - @functools.wraps(create_method) - def wrapper(client, **params): - uuid = None - error = None - try: - uuid = create_method(client, **params) - except exc.InvalidAttribute as e: - error = exc.InvalidAttribute( - 'Cannot create the %(resource)s with attributes ' - '%(params)s. One or more attributes are invalid: %(err)s' % - {'params': params, 'resource': resource_type, 'err': e} - ) - except Exception as e: - error = exc.ClientException( - 'Unable to create the %(resource)s with the specified ' - 'attributes: %(params)s. The error is: %(error)s' % - {'error': e, 'resource': resource_type, 'params': params}) - return uuid, error - return wrapper - return outer_wrapper - - -@create_single_handler('node') -def create_single_node(client, **params): - """Call the client to create a node. - - :param client: ironic client instance. - :param params: dictionary to be POSTed to /nodes endpoint, excluding - "ports" and "portgroups" keys. - :returns: UUID of the created node or None in case of exception, and an - exception, if it appears. - :raises: InvalidAttribute, if some parameters passed to client's - create_method are invalid. - :raises: ClientException, if the creation of the node fails. - """ - params.pop('ports', None) - params.pop('portgroups', None) - ret = client.node.create(**params) - return ret.uuid - - -@create_single_handler('port') -def create_single_port(client, **params): - """Call the client to create a port. - - :param client: ironic client instance. - :param params: dictionary to be POSTed to /ports endpoint. - :returns: UUID of the created port or None in case of exception, and an - exception, if it appears. - :raises: InvalidAttribute, if some parameters passed to client's - create_method are invalid. - :raises: ClientException, if the creation of the port fails. - """ - ret = client.port.create(**params) - return ret.uuid - - -@create_single_handler('port group') -def create_single_portgroup(client, **params): - """Call the client to create a port group. - - :param client: ironic client instance. - :param params: dictionary to be POSTed to /portgroups endpoint, excluding - "ports" key. - :returns: UUID of the created port group or None in case of exception, and - an exception, if it appears. - :raises: InvalidAttribute, if some parameters passed to client's - create_method are invalid. - :raises: ClientException, if the creation of the portgroup fails. - """ - params.pop('ports', None) - ret = client.portgroup.create(**params) - return ret.uuid - - -@create_single_handler('chassis') -def create_single_chassis(client, **params): - """Call the client to create a chassis. - - :param client: ironic client instance. - :param params: dictionary to be POSTed to /chassis endpoint, excluding - "nodes" key. - :returns: UUID of the created chassis or None in case of exception, and an - exception, if it appears. - :raises: InvalidAttribute, if some parameters passed to client's - create_method are invalid. - :raises: ClientException, if the creation of the chassis fails. - """ - params.pop('nodes', None) - ret = client.chassis.create(**params) - return ret.uuid - - -def create_ports(client, port_list, node_uuid, portgroup_uuid=None): - """Create ports from dictionaries. - - :param client: ironic client instance. - :param port_list: list of dictionaries to be POSTed to /ports - endpoint. - :param node_uuid: UUID of a node the ports should be associated with. - :param portgroup_uuid: UUID of a port group the ports should be associated - with, if they are its members. - :returns: array of exceptions encountered during creation. - """ - errors = [] - for port in port_list: - port_node_uuid = port.get('node_uuid') - if port_node_uuid and port_node_uuid != node_uuid: - errors.append(exc.ClientException( - 'Cannot create a port as part of node %(node_uuid)s ' - 'because the port %(port)s has a different node UUID ' - 'specified.', - {'node_uuid': node_uuid, - 'port': port})) - continue - port['node_uuid'] = node_uuid - if portgroup_uuid: - port_portgroup_uuid = port.get('portgroup_uuid') - if port_portgroup_uuid and port_portgroup_uuid != portgroup_uuid: - errors.append(exc.ClientException( - 'Cannot create a port as part of port group ' - '%(portgroup_uuid)s because the port %(port)s has a ' - 'different port group UUID specified.', - {'portgroup_uuid': portgroup_uuid, - 'port': port})) - continue - port['portgroup_uuid'] = portgroup_uuid - port_uuid, error = create_single_port(client, **port) - if error: - errors.append(error) - return errors - - -def create_portgroups(client, portgroup_list, node_uuid): - """Create port groups from dictionaries. - - :param client: ironic client instance. - :param portgroup_list: list of dictionaries to be POSTed to /portgroups - endpoint, if some of them contain "ports" key, its content is POSTed - separately to /ports endpoint. - :param node_uuid: UUID of a node the port groups should be associated with. - :returns: array of exceptions encountered during creation. - """ - errors = [] - for portgroup in portgroup_list: - portgroup_node_uuid = portgroup.get('node_uuid') - if portgroup_node_uuid and portgroup_node_uuid != node_uuid: - errors.append(exc.ClientException( - 'Cannot create a port group as part of node %(node_uuid)s ' - 'because the port group %(portgroup)s has a different node ' - 'UUID specified.', - {'node_uuid': node_uuid, - 'portgroup': portgroup})) - continue - portgroup['node_uuid'] = node_uuid - portgroup_uuid, error = create_single_portgroup(client, **portgroup) - if error: - errors.append(error) - ports = portgroup.get('ports') - # Port group UUID == None means that port group creation failed, don't - # create the ports inside it - if ports is not None and portgroup_uuid is not None: - errors.extend(create_ports(client, ports, node_uuid, - portgroup_uuid=portgroup_uuid)) - return errors - - -def create_nodes(client, node_list, chassis_uuid=None): - """Create nodes from dictionaries. - - :param client: ironic client instance. - :param node_list: list of dictionaries to be POSTed to /nodes - endpoint, if some of them contain "ports" key, its content is POSTed - separately to /ports endpoint. - :param chassis_uuid: UUID of a chassis the nodes should be associated with. - :returns: array of exceptions encountered during creation. - """ - errors = [] - for node in node_list: - if chassis_uuid is not None: - node_chassis_uuid = node.get('chassis_uuid') - if node_chassis_uuid and node_chassis_uuid != chassis_uuid: - errors.append(exc.ClientException( - 'Cannot create a node as part of chassis %(chassis_uuid)s ' - 'because the node %(node)s has a different chassis UUID ' - 'specified.' % - {'chassis_uuid': chassis_uuid, - 'node': node})) - continue - node['chassis_uuid'] = chassis_uuid - node_uuid, error = create_single_node(client, **node) - if error: - errors.append(error) - ports = node.get('ports') - portgroups = node.get('portgroups') - # Node UUID == None means that node creation failed, don't - # create the port(group)s inside it - if node_uuid is not None: - if portgroups is not None: - errors.extend( - create_portgroups(client, portgroups, node_uuid)) - if ports is not None: - errors.extend(create_ports(client, ports, node_uuid)) - return errors - - -def create_chassis(client, chassis_list): - """Create chassis from dictionaries. - - :param client: ironic client instance. - :param chassis_list: list of dictionaries to be POSTed to /chassis - endpoint, if some of them contain "nodes" key, its content is POSTed - separately to /nodes endpoint. - :returns: array of exceptions encountered during creation. - """ - errors = [] - for chassis in chassis_list: - chassis_uuid, error = create_single_chassis(client, **chassis) - if error: - errors.append(error) - nodes = chassis.get('nodes') - # Chassis UUID == None means that chassis creation failed, don't - # create the nodes inside it - if nodes is not None and chassis_uuid is not None: - errors.extend(create_nodes(client, nodes, - chassis_uuid=chassis_uuid)) - return errors diff --git a/ironicclient/v1/create_resources_shell.py b/ironicclient/v1/create_resources_shell.py deleted file mode 100644 index 03c8628..0000000 --- a/ironicclient/v1/create_resources_shell.py +++ /dev/null @@ -1,28 +0,0 @@ -# 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 ironicclient.common import cliutils -from ironicclient.v1 import create_resources - - -@cliutils.arg('resource_files', nargs='+', metavar='', default=[], - help='File (.yaml or .json) containing descriptions of the ' - 'resources to create. Can be specified multiple times.') -def do_create(cc, args): - """Create baremetal resources (chassis, nodes, port groups and ports). - - The resources may be described in one or more JSON or YAML files. If any - file cannot be validated, no resources are created. An attempt is made to - create all the resources; those that could not be created are skipped - (with a corresponding error message). - """ - create_resources.create_resources(cc, args.resource_files) diff --git a/ironicclient/v1/driver.py b/ironicclient/v1/driver.py deleted file mode 100644 index 586d125..0000000 --- a/ironicclient/v1/driver.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2013 Red Hat, 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 ironicclient.common import base -from ironicclient.common.i18n import _ -from ironicclient import exc - - -class Driver(base.Resource): - def __repr__(self): - return "" % self._info - - -class DriverManager(base.Manager): - resource_class = Driver - _resource_name = 'drivers' - - def list(self, driver_type=None, detail=None): - """Retrieve a list of drivers. - - :param driver_type: Optional, string to filter the drivers by type. - Value should be 'classic' or 'dynamic'. - :param detail: Optional, flag whether to return detailed information - about drivers. Default is None means not to send the arg - to the server due to older versions of the server cannot - handle filtering on detail. - :returns: A list of drivers. - """ - filters = [] - if driver_type is not None: - filters.append('type=%s' % driver_type) - if detail is not None: - filters.append('detail=%s' % detail) - - path = '' - if filters: - path = '?' + '&'.join(filters) - - return self._list(self._path(path), self._resource_name) - - def get(self, driver_name): - return self._get(resource_id=driver_name) - - def update(self, driver_name, patch, http_method='PATCH'): - return self._update(resource_id=driver_name, patch=patch, - method=http_method) - - def delete(self, driver_name): - return self._delete(resource_id=driver_name) - - def properties(self, driver_name): - return self._get_as_dict('%s/properties' % driver_name) - - def raid_logical_disk_properties(self, driver_name): - """Returns the RAID logical disk properties for the driver. - - :param driver_name: Name of the driver. - :returns: A dictionary containing the properties that can be mentioned - for RAID logical disks and a textual description for them. It - returns an empty dictionary on error. - """ - info = None - try: - info = self._list( - '/v1/drivers/%s/raid/logical_disk_properties' % driver_name)[0] - except IndexError: - pass - - if info: - return info.to_dict() - return {} - - def vendor_passthru(self, driver_name, method, args=None, - http_method=None): - """Issue requests for vendor-specific actions on a given driver. - - :param driver_name: The name of the driver. - :param method: Name of the vendor method. - :param args: Optional. The arguments to be passed to the method. - :param http_method: The HTTP method to use on the request. - Defaults to POST. - """ - if args is None: - args = {} - - if http_method is None: - http_method = 'POST' - - http_method = http_method.upper() - - path = "%s/vendor_passthru/%s" % (driver_name, method) - if http_method in ('POST', 'PUT', 'PATCH'): - return self.update(path, args, http_method=http_method) - elif http_method == 'DELETE': - return self.delete(path) - elif http_method == 'GET': - return self.get(path) - else: - raise exc.InvalidAttribute( - _('Unknown HTTP method: %s') % http_method) - - def get_vendor_passthru_methods(self, driver_name): - return self._get_as_dict("%s/vendor_passthru/methods" % driver_name) diff --git a/ironicclient/v1/driver_shell.py b/ironicclient/v1/driver_shell.py deleted file mode 100644 index ba85776..0000000 --- a/ironicclient/v1/driver_shell.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2013 Red Hat, 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 argparse - -from ironicclient.common import cliutils -from ironicclient.common import utils -from ironicclient.v1 import resource_fields as res_fields -from ironicclient.v1 import utils as v1_utils - - -def _print_driver_show(driver, json=False): - fields = res_fields.DRIVER_DETAILED_RESOURCE.fields - data = dict([(f, getattr(driver, f, '')) for f in fields]) - cliutils.print_dict(data, wrap=72, json_flag=json) - - -@cliutils.arg('-t', '--type', - metavar='', - choices=["classic", "dynamic"], - help='Type of driver ("classic" or "dynamic"). ' - 'The default is to list all of them.') -@cliutils.arg('--detail', - dest='detail', - action='store_true', - default=None, - help="Show detailed information about the drivers.") -def do_driver_list(cc, args): - """List the enabled drivers.""" - drivers = cc.driver.list(driver_type=args.type, detail=args.detail) - # NOTE(lucasagomes): For list-type properties, show the values as - # comma separated strings. It's easier to read. - data = [utils.convert_list_props_to_comma_separated(d._info) - for d in drivers] - - if args.detail: - field_labels = res_fields.DRIVER_DETAILED_RESOURCE.labels - fields = res_fields.DRIVER_DETAILED_RESOURCE.fields - else: - field_labels = res_fields.DRIVER_RESOURCE.labels - fields = res_fields.DRIVER_RESOURCE.fields - - cliutils.print_list(data, fields, field_labels=field_labels, - json_flag=args.json) - - -@cliutils.arg('driver_name', metavar='', - help='Name of the driver.') -def do_driver_show(cc, args): - """Show information about a driver.""" - driver = cc.driver.get(args.driver_name) - _print_driver_show(driver, json=args.json) - - -@cliutils.arg('driver_name', metavar='', - help="Name of the driver.") -@cliutils.arg('--wrap', dest='wrap', metavar='', - type=int, default=0, - help=('Wrap the output to a specified length. ' - 'Positive number can realize wrap functionality. ' - '0 is default for disabled.')) -def do_driver_properties(cc, args): - """Get properties of a driver.""" - properties = cc.driver.properties(args.driver_name) - cliutils.print_dict( - properties, - wrap=args.wrap, - dict_value='Description', - json_flag=args.json) - - -@cliutils.arg('driver_name', metavar='', - help="Name of the driver.") -@cliutils.arg('--wrap', dest='wrap', metavar='', - type=int, default=0, - help=('Wrap the output to a specified length. ' - 'Positive number can realize wrap functionality. ' - '0 is default for disabled.')) -def do_driver_raid_logical_disk_properties(cc, args): - """Get RAID logical disk properties for a driver.""" - properties = cc.driver.raid_logical_disk_properties(args.driver_name) - cliutils.print_dict( - properties, - wrap=args.wrap, - dict_value='Description') - - -@cliutils.arg('driver_name', - metavar='', - help='Name of the driver.') -@cliutils.arg('method', - metavar='', - help="Vendor-passthru method to be called.") -@cliutils.arg('arguments', - metavar='', - nargs='*', - action='append', - default=[], - help="Argument to be passed to the vendor-passthru method. " - "Can be specified multiple times.") -@cliutils.arg('--http-method', - metavar='', - choices=v1_utils.HTTP_METHODS, - help=("The HTTP method to use in the request. Valid HTTP " - "methods are: %s. Defaults to 'POST'." % - ', '.join(v1_utils.HTTP_METHODS))) -@cliutils.arg('--http_method', - help=argparse.SUPPRESS) -def do_driver_vendor_passthru(cc, args): - """Call a vendor-passthru extension for a driver.""" - arguments = utils.key_value_pairs_to_dict(args.arguments[0]) - - resp = cc.driver.vendor_passthru(args.driver_name, args.method, - http_method=args.http_method, - args=arguments) - if resp: - # Print the raw response we don't know how it should be formated - print(str(resp.to_dict())) - - -@cliutils.arg('driver_name', - metavar='', - help='Name of the driver.') -def do_driver_get_vendor_passthru_methods(cc, args): - """Get the vendor passthru methods for a driver.""" - methods = cc.driver.get_vendor_passthru_methods(args.driver_name) - data = [] - for method, response in methods.items(): - response['name'] = method - http_methods = ','.join(response['http_methods']) - response['http_methods'] = http_methods - data.append(response) - fields = res_fields.VENDOR_PASSTHRU_METHOD_RESOURCE.fields - field_labels = res_fields.VENDOR_PASSTHRU_METHOD_RESOURCE.labels - cliutils.print_list(data, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) diff --git a/ironicclient/v1/node.py b/ironicclient/v1/node.py deleted file mode 100644 index 192d6e7..0000000 --- a/ironicclient/v1/node.py +++ /dev/null @@ -1,628 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os -import time - -from oslo_utils import strutils - -from ironicclient.common import base -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.v1 import volume_connector -from ironicclient.v1 import volume_target - -_power_states = { - 'on': 'power on', - 'off': 'power off', - 'reboot': 'rebooting', - 'soft off': 'soft power off', - 'soft reboot': 'soft rebooting', -} - - -LOG = logging.getLogger(__name__) -_DEFAULT_POLL_INTERVAL = 2 - - -class Node(base.Resource): - def __repr__(self): - return "" % self._info - - -class NodeManager(base.CreateManager): - resource_class = Node - _creation_attributes = ['chassis_uuid', 'driver', 'driver_info', - 'extra', 'uuid', 'properties', 'name', - 'boot_interface', 'console_interface', - 'deploy_interface', 'inspect_interface', - 'management_interface', 'network_interface', - 'power_interface', 'raid_interface', - 'storage_interface', 'vendor_interface', - 'resource_class'] - _resource_name = 'nodes' - - def list(self, associated=None, maintenance=None, marker=None, limit=None, - detail=False, sort_key=None, sort_dir=None, fields=None, - provision_state=None, driver=None, resource_class=None, - chassis=None): - """Retrieve a list of nodes. - - :param associated: Optional. Either a Boolean or a string - representation of a Boolean that indicates whether - to return a list of associated (True or "True") or - unassociated (False or "False") nodes. - :param maintenance: Optional. Either a Boolean or a string - representation of a Boolean that indicates whether - to return nodes in maintenance mode (True or - "True"), or not in maintenance mode (False or - "False"). - :param provision_state: Optional. String value to get only nodes in - that provision state. - :param marker: Optional, the UUID of a node, eg the last - node from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of nodes to return. - 2) limit == 0, return the entire list of nodes. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param detail: Optional, boolean whether to return detailed information - about nodes. - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :param driver: Optional. String value to get only nodes using that - driver. - - :param resource_class: Optional. String value to get only nodes - with the given resource class set. - - :param chassis: Optional, the UUID of a chassis. Used to get only - nodes of this chassis. - - :returns: A list of nodes. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker, limit, sort_key, sort_dir, - fields) - if associated is not None: - filters.append('associated=%s' % associated) - if maintenance is not None: - filters.append('maintenance=%s' % maintenance) - if provision_state is not None: - filters.append('provision_state=%s' % provision_state) - if driver is not None: - filters.append('driver=%s' % driver) - if resource_class is not None: - filters.append('resource_class=%s' % resource_class) - if chassis is not None: - filters.append('chassis_uuid=%s' % chassis) - - path = '' - if detail: - path += 'detail' - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "nodes") - else: - return self._list_pagination(self._path(path), "nodes", - limit=limit) - - def list_ports(self, node_id, marker=None, limit=None, sort_key=None, - sort_dir=None, detail=False, fields=None): - """List all the ports for a given node. - - :param node_id: Name or UUID of the node. - :param marker: Optional, the UUID of a port, eg the last - port from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of ports to return. - 2) limit == 0, return the entire list of ports. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about ports. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: A list of ports. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker, limit, sort_key, sort_dir, - fields) - - path = "%s/ports" % node_id - if detail: - path += '/detail' - - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "ports") - else: - return self._list_pagination(self._path(path), "ports", - limit=limit) - - def list_volume_connectors(self, node_id, marker=None, limit=None, - sort_key=None, sort_dir=None, detail=False, - fields=None): - """List all the volume connectors for a given node. - - :param node_id: Name or UUID of the node. - :param marker: Optional, the UUID of a volume connector, eg the last - volume connector from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of volume connectors to return. - 2) limit == 0, return the entire list of volume connectors. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about volume connectors. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: A list of volume connectors. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker=marker, limit=limit, - sort_key=sort_key, sort_dir=sort_dir, - fields=fields, detail=detail) - - path = "%s/volume/connectors" % node_id - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), response_key="connectors", - obj_class=volume_connector.VolumeConnector) - else: - return self._list_pagination( - self._path(path), response_key="connectors", limit=limit, - obj_class=volume_connector.VolumeConnector) - - def list_volume_targets(self, node_id, marker=None, limit=None, - sort_key=None, sort_dir=None, detail=False, - fields=None): - """List all the volume targets for a given node. - - :param node_id: Name or UUID of the node. - :param marker: Optional, the UUID of a volume target, eg the last - volume target from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of volume targets to return. - 2) limit == 0, return the entire list of volume targets. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about volume targets. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: A list of volume targets. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker=marker, limit=limit, - sort_key=sort_key, sort_dir=sort_dir, - fields=fields, detail=detail) - - path = "%s/volume/targets" % node_id - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), response_key="targets", - obj_class=volume_target.VolumeTarget) - else: - return self._list_pagination( - self._path(path), response_key="targets", limit=limit, - obj_class=volume_target.VolumeTarget) - - def get(self, node_id, fields=None): - return self._get(resource_id=node_id, fields=fields) - - def get_by_instance_uuid(self, instance_uuid, fields=None): - path = '?instance_uuid=%s' % instance_uuid - if fields is not None: - path += '&fields=' + ','.join(fields) - else: - path = 'detail' + path - - nodes = self._list(self._path(path), 'nodes') - # get all the details of the node assuming that - # filtering by instance_uuid returns a collection - # of one node if successful. - if len(nodes) == 1: - return nodes[0] - else: - raise exc.NotFound() - - def delete(self, node_id): - return self._delete(resource_id=node_id) - - def update(self, node_id, patch, http_method='PATCH'): - return self._update(resource_id=node_id, patch=patch, - method=http_method) - - def vendor_passthru(self, node_id, method, args=None, - http_method=None): - """Issue requests for vendor-specific actions on a given node. - - :param node_id: The UUID of the node. - :param method: Name of the vendor method. - :param args: Optional. The arguments to be passed to the method. - :param http_method: The HTTP method to use on the request. - Defaults to POST. - """ - if args is None: - args = {} - - if http_method is None: - http_method = 'POST' - - http_method = http_method.upper() - - path = "%s/vendor_passthru/%s" % (node_id, method) - if http_method in ('POST', 'PUT', 'PATCH'): - return self.update(path, args, http_method=http_method) - elif http_method == 'DELETE': - return self.delete(path) - elif http_method == 'GET': - return self.get(path) - else: - raise exc.InvalidAttribute( - _('Unknown HTTP method: %s') % http_method) - - def vif_list(self, node_ident): - """List VIFs attached to a given node. - - :param node_ident: The UUID or Name of the node. - """ - path = "%s/vifs" % node_ident - - return self._list(self._path(path), "vifs") - - def vif_attach(self, node_ident, vif_id, **kwargs): - """Attach VIF to a given node. - - param node_ident: The UUID or Name of the node. - param vif_id: The UUID or Name of the VIF to attach. - :param kwargs: A dictionary containing the attributes of the resource - that will be created. - """ - path = "%s/vifs" % node_ident - data = {"id": vif_id} - if 'id' in kwargs: - raise exc.InvalidAttribute("The attribute 'id' can't be " - "specified in vif-info") - data.update(kwargs) - # TODO(vdrok): cleanup places doing custom path and http_method - self.update(path, data, http_method="POST") - - def vif_detach(self, node_ident, vif_id): - """Detach VIF from a given node. - - param node_ident: The UUID or Name of the node. - param vif_id: The UUID or Name of the VIF to detach. - """ - path = "%s/vifs/%s" % (node_ident, vif_id) - self.delete(path) - - def set_maintenance(self, node_id, state, maint_reason=None): - """Set the maintenance mode for the node. - - :param node_id: The UUID of the node. - :param state: the maintenance mode; either a Boolean or a string - representation of a Boolean (eg, 'true', 'on', 'false', - 'off'). True to put the node in maintenance mode; False - to take the node out of maintenance mode. - :param maint_reason: Optional string. Reason for putting node - into maintenance mode. - :raises: InvalidAttribute if state is an invalid string (that doesn't - represent a Boolean). - - """ - if isinstance(state, bool): - maintenance_mode = state - else: - try: - maintenance_mode = strutils.bool_from_string(state, True) - except ValueError as e: - raise exc.InvalidAttribute(_("Argument 'state': %(err)s") % - {'err': e}) - path = "%s/maintenance" % node_id - if maintenance_mode: - reason = {'reason': maint_reason} - return self.update(path, reason, http_method='PUT') - else: - return self.delete(path) - - def set_power_state(self, node_id, state, soft=False, timeout=None): - """Sets power state for a node. - - :param node_id: Node identifier - :param state: One of target power state, 'on', 'off', or 'reboot' - :param soft: The flag for graceful power 'off' or 'reboot' - :param timeout: The timeout (in seconds) positive integer value (> 0) - :raises: ValueError if 'soft' or 'timeout' option is invalid - :returns: The status of the request - """ - if state == 'on' and soft: - raise ValueError( - _("'soft' option is invalid for the power-state 'on'")) - - path = "%s/states/power" % node_id - - requested_state = 'soft ' + state if soft else state - target = _power_states.get(requested_state, state) - - body = {'target': target} - if timeout is not None: - msg = _("'timeout' option for setting power state must have " - "positive integer value (> 0)") - try: - timeout = int(timeout) - except (ValueError, TypeError): - raise ValueError(msg) - - if timeout <= 0: - raise ValueError(msg) - body = {'target': target, 'timeout': timeout} - - return self.update(path, body, http_method='PUT') - - def set_target_raid_config(self, node_ident, target_raid_config): - """Sets target_raid_config for a node. - - :param node_ident: Node identifier - :param target_raid_config: A dictionary with the target RAID - configuration; may be empty. - :returns: status of the request - """ - path = "%s/states/raid" % node_ident - return self.update(path, target_raid_config, http_method='PUT') - - def validate(self, node_uuid): - path = "%s/validate" % node_uuid - return self.get(path) - - def set_provision_state(self, node_uuid, state, configdrive=None, - cleansteps=None): - """Set the provision state for the node. - - :param node_uuid: The UUID or name of the node. - :param state: The desired provision state. One of 'active', 'deleted', - 'rebuild', 'inspect', 'provide', 'manage', 'clean', 'abort'. - :param configdrive: A gzipped, base64-encoded configuration drive - string OR the path to the configuration drive file OR the path to - a directory containing the config drive files. In case it's a - directory, a config drive will be generated from it. This is only - valid when setting state to 'active'. - :param cleansteps: The clean steps as a list of clean-step - dictionaries; each dictionary should have keys 'interface' and - 'step', and optional key 'args'. This must be specified (and is - only valid) when setting provision-state to 'clean'. - :raises: InvalidAttribute if there was an error with the clean steps - :returns: The status of the request - """ - - path = "%s/states/provision" % node_uuid - body = {'target': state} - if configdrive: - if os.path.isfile(configdrive): - with open(configdrive, 'rb') as f: - configdrive = f.read() - if os.path.isdir(configdrive): - configdrive = utils.make_configdrive(configdrive) - - body['configdrive'] = configdrive - elif cleansteps: - body['clean_steps'] = cleansteps - - return self.update(path, body, http_method='PUT') - - def states(self, node_uuid): - path = "%s/states" % node_uuid - return self.get(path) - - def get_console(self, node_uuid): - path = "%s/states/console" % node_uuid - return self._get_as_dict(path) - - def set_console_mode(self, node_uuid, enabled): - """Set the console mode for the node. - - :param node_uuid: The UUID of the node. - :param enabled: Either a Boolean or a string representation of a - Boolean. True to enable the console; False to disable. - - """ - path = "%s/states/console" % node_uuid - target = {'enabled': enabled} - return self.update(path, target, http_method='PUT') - - def set_boot_device(self, node_uuid, boot_device, persistent=False): - path = "%s/management/boot_device" % node_uuid - target = {'boot_device': boot_device, 'persistent': persistent} - return self.update(path, target, http_method='PUT') - - def get_boot_device(self, node_uuid): - path = "%s/management/boot_device" % node_uuid - return self._get_as_dict(path) - - def inject_nmi(self, node_uuid): - path = "%s/management/inject_nmi" % node_uuid - return self.update(path, {}, http_method='PUT') - - def get_supported_boot_devices(self, node_uuid): - path = "%s/management/boot_device/supported" % node_uuid - return self._get_as_dict(path) - - def get_vendor_passthru_methods(self, node_ident): - path = "%s/vendor_passthru/methods" % node_ident - return self._get_as_dict(path) - - def wait_for_provision_state(self, node_ident, expected_state, - timeout=0, - poll_interval=_DEFAULT_POLL_INTERVAL, - poll_delay_function=None, - fail_on_unexpected_state=True): - """Helper function to wait for a node to reach a given state. - - Polls Ironic API in a loop until node gets to a requested state. - - Fails in the following cases: - * Timeout (if provided) is reached - * Node's last_error gets set to a non-empty value - * Unexpected stable state is reached and fail_on_unexpected_state is on - * Error state is reached (if it's not equal to expected_state) - - :param node_ident: node UUID or name - :param expected_state: expected final provision state - :param timeout: timeout in seconds, no timeout if 0 - :param poll_interval: interval in seconds between 2 poll - :param poll_delay_function: function to use to wait between polls - (defaults to time.sleep). Should take one argument - delay time - in seconds. Any exceptions raised inside it will abort the wait. - :param fail_on_unexpected_state: whether to fail if the nodes - reaches a different stable state. - :raises: StateTransitionFailed if node reached an error state - :raises: StateTransitionTimeout on timeout - """ - if not isinstance(timeout, (int, float)) or timeout < 0: - raise ValueError(_('Timeout must be a non-negative number')) - - threshold = time.time() + timeout - expected_state = expected_state.lower() - poll_delay_function = (time.sleep if poll_delay_function is None - else poll_delay_function) - if not callable(poll_delay_function): - raise TypeError(_('poll_delay_function must be callable')) - - # TODO(dtantsur): use version negotiation to request API 1.8 and use - # the "fields" argument to reduce amount of data sent. - while not timeout or time.time() < threshold: - node = self.get(node_ident) - if node.provision_state == expected_state: - LOG.debug('Node %(node)s reached provision state %(state)s', - {'node': node_ident, 'state': expected_state}) - return - - # Note that if expected_state == 'error' we still succeed - if (node.last_error or node.provision_state == 'error' or - node.provision_state.endswith(' failed')): - raise exc.StateTransitionFailed( - _('Node %(node)s failed to reach state %(state)s. ' - 'It\'s in state %(actual)s, and has error: %(error)s') % - {'node': node_ident, 'state': expected_state, - 'actual': node.provision_state, 'error': node.last_error}) - - if fail_on_unexpected_state and not node.target_provision_state: - raise exc.StateTransitionFailed( - _('Node %(node)s failed to reach state %(state)s. ' - 'It\'s in unexpected stable state %(actual)s') % - {'node': node_ident, 'state': expected_state, - 'actual': node.provision_state}) - - LOG.debug('Still waiting for node %(node)s to reach state ' - '%(state)s, the current state is %(actual)s', - {'node': node_ident, 'state': expected_state, - 'actual': node.provision_state}) - poll_delay_function(poll_interval) - - raise exc.StateTransitionTimeout( - _('Node %(node)s failed to reach state %(state)s in ' - '%(timeout)s seconds') % {'node': node_ident, - 'state': expected_state, - 'timeout': timeout}) diff --git a/ironicclient/v1/node_shell.py b/ironicclient/v1/node_shell.py deleted file mode 100644 index 8f0713f..0000000 --- a/ironicclient/v1/node_shell.py +++ /dev/null @@ -1,716 +0,0 @@ -# Copyright 2013 Red Hat, 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 argparse -import six - -from ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc -from ironicclient.v1 import resource_fields as res_fields -from ironicclient.v1 import utils as v1_utils - - -def _print_node_show(node, fields=None, json=False): - if fields is None: - fields = res_fields.NODE_DETAILED_RESOURCE.fields - - data = dict( - [(f, getattr(node, f, '')) for f in fields]) - cliutils.print_dict(data, wrap=72, json_flag=json) - - -@cliutils.arg( - 'node', - metavar='', - help="Name or UUID of the node " - "(or instance UUID if --instance is specified).") -@cliutils.arg( - '--instance', - dest='instance_uuid', - action='store_true', - default=False, - help=' is an instance UUID.') -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more node fields. Only these fields will be fetched from " - "the server.") -def do_node_show(cc, args): - """Show detailed information about a node.""" - fields = args.fields[0] if args.fields else None - utils.check_empty_arg(args.node, '') - utils.check_for_invalid_fields( - fields, res_fields.NODE_DETAILED_RESOURCE.fields) - if args.instance_uuid: - node = cc.node.get_by_instance_uuid(args.node, fields=fields) - else: - node = cc.node.get(args.node, fields=fields) - _print_node_show(node, fields=fields, json=args.json) - - -@cliutils.arg( - '--limit', - metavar='', - type=int, - help='Maximum number of nodes to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Ironic API Service.') -@cliutils.arg( - '--marker', - metavar='', - help='Node UUID (for example, of the last node in the list from ' - 'a previous request). Returns the list of nodes after this UUID.') -@cliutils.arg( - '--sort-key', - metavar='', - help='Node field that will be used for sorting.') -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help='Sort direction: "asc" (the default) or "desc".') -@cliutils.arg( - '--maintenance', - metavar='', - help="List nodes in maintenance mode: 'true' or 'false'.") -@cliutils.arg( - '--associated', - metavar='', - help="List nodes by instance association: 'true' or 'false'.") -@cliutils.arg( - '--provision-state', - metavar='', - help="List nodes in specified provision state.") -@cliutils.arg( - '--driver', - metavar='', - help="List nodes using specified driver.") -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help="Show detailed information about the nodes.") -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more node fields. Only these fields will be fetched from " - "the server. Can not be used when '--detail' is specified.") -@cliutils.arg( - '--resource-class', - dest='resource_class', - metavar='', - help="List nodes using specified resource class.") -def do_node_list(cc, args): - """List the nodes which are registered with the Ironic service.""" - params = {} - if args.associated is not None: - params['associated'] = utils.bool_argument_value("--associated", - args.associated) - if args.maintenance is not None: - params['maintenance'] = utils.bool_argument_value("--maintenance", - args.maintenance) - if args.provision_state is not None: - params['provision_state'] = args.provision_state - - if args.driver is not None: - params['driver'] = args.driver - - if args.resource_class is not None: - params['resource_class'] = args.resource_class - - if args.detail: - fields = res_fields.NODE_DETAILED_RESOURCE.fields - field_labels = res_fields.NODE_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], res_fields.NODE_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.NODE_RESOURCE.fields - field_labels = res_fields.NODE_RESOURCE.labels - - sort_fields = res_fields.NODE_DETAILED_RESOURCE.sort_fields - sort_field_labels = res_fields.NODE_DETAILED_RESOURCE.sort_labels - - params.update(utils.common_params_for_list(args, - sort_fields, - sort_field_labels)) - nodes = cc.node.list(**params) - cliutils.print_list(nodes, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg( - '-c', '--chassis', - dest='chassis_uuid', - metavar='', - help='UUID of the chassis that this node belongs to.') -@cliutils.arg( - '--chassis_uuid', - help=argparse.SUPPRESS) -@cliutils.arg( - '-d', '--driver', - metavar='', - required=True, - help='Driver used to control the node.') -@cliutils.arg( - '-i', '--driver-info', - metavar='', - action='append', - help='Key/value pair used by the driver, such as out-of-band management ' - 'credentials. Can be specified multiple times.') -@cliutils.arg( - '--driver_info', - action='append', - help=argparse.SUPPRESS) -@cliutils.arg( - '-p', '--properties', - metavar='', - action='append', - help='Key/value pair describing the physical characteristics of the ' - 'node. This is exported to Nova and used by the scheduler. ' - 'Can be specified multiple times.') -@cliutils.arg( - '-e', '--extra', - metavar='', - action='append', - help="Record arbitrary key/value metadata. " - "Can be specified multiple times.") -@cliutils.arg( - '-u', '--uuid', - metavar='', - help="Unique UUID for the node.") -@cliutils.arg( - '-n', '--name', - metavar='', - help="Unique name for the node.") -@cliutils.arg( - '--boot-interface', - metavar='', - help='Boot interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.') -@cliutils.arg( - '--console-interface', - metavar='', - help='Console interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.') -@cliutils.arg( - '--deploy-interface', - metavar='', - help='Deploy interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.') -@cliutils.arg( - '--inspect-interface', - metavar='', - help='Inspect interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.') -@cliutils.arg( - '--management-interface', - metavar='', - help='Management interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.') -@cliutils.arg( - '--network-interface', - metavar='', - help='Network interface used for switching node to cleaning/provisioning ' - 'networks.') -@cliutils.arg( - '--power-interface', - metavar='', - help='Power interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.') -@cliutils.arg( - '--raid-interface', - metavar='', - help='RAID interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.') -@cliutils.arg( - '--storage-interface', - metavar='', - help='Storage interface used by the node\'s driver.') -@cliutils.arg( - '--vendor-interface', - metavar='', - help='Vendor interface used by the node\'s driver. This is ' - 'only applicable when the specified --driver is a ' - 'hardware type.') -@cliutils.arg( - '--resource-class', - metavar='', - help='Resource class for classifying or grouping nodes. Used, for ' - 'example, to classify nodes in Nova\'s placement engine.') -def do_node_create(cc, args): - """Register a new node with the Ironic service.""" - field_list = ['chassis_uuid', 'driver', 'driver_info', - 'properties', 'extra', 'uuid', 'name', - 'boot_interface', 'console_interface', - 'deploy_interface', 'inspect_interface', - 'management_interface', 'network_interface', - 'power_interface', 'raid_interface', - 'storage_interface', 'vendor_interface', - 'resource_class'] - fields = dict((k, v) for (k, v) in vars(args).items() - if k in field_list and not (v is None)) - fields = utils.args_array_to_dict(fields, 'driver_info') - fields = utils.args_array_to_dict(fields, 'extra') - fields = utils.args_array_to_dict(fields, 'properties') - node = cc.node.create(**fields) - - data = dict([(f, getattr(node, f, '')) for f in field_list]) - cliutils.print_dict(data, wrap=72, json_flag=args.json) - - -@cliutils.arg('node', - metavar='', - nargs='+', - help="Name or UUID of the node.") -def do_node_delete(cc, args): - """Unregister node(s) from the Ironic service. - - Returns errors for any nodes that could not be unregistered. - """ - - failures = [] - for n in args.node: - try: - cc.node.delete(n) - print(_('Deleted node %s') % n) - except exceptions.ClientException as e: - failures.append(_("Failed to delete node %(node)s: %(error)s") - % {'node': n, 'error': e}) - if failures: - raise exceptions.ClientException("\n".join(failures)) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg( - 'op', - metavar='', - choices=['add', 'replace', 'remove'], - help="Operation: 'add', 'replace', or 'remove'.") -@cliutils.arg( - 'attributes', - metavar='', - nargs='+', - action='append', - default=[], - help="Attribute to add, replace, or remove. Can be specified " - "multiple times. For 'remove', only is necessary. " - "For nested attributes, separate the components with slashes, eg " - "'driver_info/deploy_kernel=uuid'.") -def do_node_update(cc, args): - """Update information about a registered node.""" - patch = utils.args_array_to_patch(args.op, args.attributes[0]) - node = cc.node.update(args.node, patch) - _print_node_show(node, json=args.json) - - -@cliutils.arg('node', - metavar='', - help="Name or UUID of the node.") -@cliutils.arg('method', - metavar='', - help="Vendor-passthru method to be called.") -@cliutils.arg('arguments', - metavar='', - nargs='*', - action='append', - default=[], - help=("Argument to be passed to the vendor-passthru method. Can " - "be specified multiple times.")) -@cliutils.arg('--http-method', - metavar='', - choices=v1_utils.HTTP_METHODS, - help=("The HTTP method to use in the request. Valid HTTP " - "methods are: %s. Defaults to 'POST'." % - ', '.join(v1_utils.HTTP_METHODS))) -@cliutils.arg('--http_method', - help=argparse.SUPPRESS) -def do_node_vendor_passthru(cc, args): - """Call a vendor-passthru extension for a node.""" - arguments = utils.key_value_pairs_to_dict(args.arguments[0]) - - resp = cc.node.vendor_passthru(args.node, args.method, - http_method=args.http_method, - args=arguments) - if resp: - # Print the raw response we don't know how it should be formated - print(str(resp.to_dict())) - - -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help="Show detailed information about the ports.") -@cliutils.arg( - '--limit', - metavar='', - type=int, - help='Maximum number of ports to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Ironic API Service.') -@cliutils.arg( - '--marker', - metavar='', - help='Port UUID (for example, of the last port in the list from a ' - 'previous request). Returns the list of ports after this UUID.') -@cliutils.arg( - '--sort-key', - metavar='', - help='Port field that will be used for sorting.') -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help='Sort direction: "asc" (the default) or "desc".') -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more port fields. Only these fields will be fetched from " - "the server. Can not be used when '--detail' is specified.") -def do_node_port_list(cc, args): - """List the ports associated with a node.""" - if args.detail: - fields = res_fields.PORT_DETAILED_RESOURCE.fields - field_labels = res_fields.PORT_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], res_fields.PORT_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.PORT_RESOURCE.fields - field_labels = res_fields.PORT_RESOURCE.labels - - sort_fields = res_fields.PORT_DETAILED_RESOURCE.sort_fields - sort_field_labels = res_fields.PORT_DETAILED_RESOURCE.sort_labels - - params = utils.common_params_for_list(args, sort_fields, - sort_field_labels) - - ports = cc.node.list_ports(args.node, **params) - - cliutils.print_list(ports, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg( - 'maintenance_mode', - metavar='', - help="'true' or 'false'; 'on' or 'off'.") -@cliutils.arg( - '--reason', - metavar='', - default=None, - help=("Reason for setting maintenance mode to 'true' or 'on';" - " not valid when setting to 'false' or 'off'.")) -def do_node_set_maintenance(cc, args): - """Enable or disable maintenance mode for a node.""" - maintenance_mode = utils.bool_argument_value("", - args.maintenance_mode) - if args.reason and not maintenance_mode: - raise exceptions.CommandError(_('Cannot set "reason" when turning off ' - 'maintenance mode.')) - cc.node.set_maintenance(args.node, maintenance_mode, - maint_reason=args.reason) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg( - 'power_state', - metavar='', - choices=['on', 'off', 'reboot'], - help="'on', 'off', or 'reboot'.") -@cliutils.arg( - '--soft', - dest='soft', - action='store_true', - default=False, - help=("Gracefully change the power state. Only valid for 'off' and " - "'reboot' power states.")) -@cliutils.arg( - '--power-timeout', - metavar='', - type=int, - default=None, - help=("Timeout (in seconds, positive integer) to wait for the target " - "power state before erroring out.")) -def do_node_set_power_state(cc, args): - """Power a node on or off or reboot.""" - try: - cc.node.set_power_state(args.node, args.power_state, args.soft, - timeout=args.power_timeout) - except ValueError as e: - raise exc.CommandError(six.text_type(e)) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg( - 'target_raid_config', - metavar='', - help=("A file containing JSON data of the desired RAID configuration. " - "Use '-' to read the contents from standard input. " - "It also accepts the valid json string as input if " - "file/standard input are not used for providing input. " - "The input can be an empty dictionary too which " - "unsets the node.target_raid_config on the node.")) -def do_node_set_target_raid_config(cc, args): - """Set target RAID config on a node.""" - target_raid_config = args.target_raid_config - if not target_raid_config: - raise exc.InvalidAttribute( - _("target RAID configuration not provided")) - - if target_raid_config == '-': - target_raid_config = utils.get_from_stdin('target_raid_config') - target_raid_config = utils.handle_json_or_file_arg(target_raid_config) - - cc.node.set_target_raid_config(args.node, target_raid_config) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg( - 'provision_state', - metavar='', - choices=v1_utils.PROVISION_STATES, - help="Supported states: %s." % ', '.join(v1_utils.PROVISION_STATES)) -@cliutils.arg( - '--config-drive', - metavar='', - default=None, - help=("A gzipped, base64-encoded configuration drive string OR the path " - "to the configuration drive file OR the path to a directory " - "containing the config drive files. In case it's a directory, a " - "config drive will be generated from it. This argument is only " - "valid when setting provision-state to 'active'.")) -@cliutils.arg( - '--clean-steps', - metavar='', - default=None, - help=("The clean steps in JSON format. May be the path to a file " - "containing the clean steps; OR '-', with the clean steps being " - "read from standard input; OR a string. The value should be " - "a list of clean-step dictionaries; each dictionary should have " - "keys 'interface' and 'step', and optional key 'args'. " - "This argument must be specified (and is only valid) when " - "setting provision-state to 'clean'.")) -@cliutils.arg( - '--wait', - type=int, - dest='wait_timeout', - default=None, - const=0, - nargs='?', - help=("Wait for a node to reach the expected state. Not supported " - "for 'abort'. Optionally takes a timeout in seconds. " - "The default value is 0, meaning no timeout. " - "Fails if the node reaches an unexpected stable state, a failure " - "state or a state with last_error set.")) -def do_node_set_provision_state(cc, args): - """Initiate a provisioning state change for a node.""" - if args.config_drive and args.provision_state != 'active': - raise exceptions.CommandError(_('--config-drive is only valid when ' - 'setting provision state to "active"')) - elif args.clean_steps and args.provision_state != 'clean': - raise exceptions.CommandError(_('--clean-steps is only valid when ' - 'setting provision state to "clean"')) - elif args.provision_state == 'clean' and not args.clean_steps: - raise exceptions.CommandError(_('--clean-steps must be specified when ' - 'setting provision state to "clean"')) - - if args.wait_timeout is not None: - wait_args = v1_utils.PROVISION_ACTIONS.get(args.provision_state) - if wait_args is None: - raise exceptions.CommandError( - _("--wait is not supported for provision state '%s'") - % args.provision_state) - - clean_steps = args.clean_steps - if args.clean_steps == '-': - clean_steps = utils.get_from_stdin('clean steps') - if clean_steps: - clean_steps = utils.handle_json_or_file_arg(clean_steps) - cc.node.set_provision_state(args.node, args.provision_state, - configdrive=args.config_drive, - cleansteps=clean_steps) - if args.wait_timeout is not None: - print(_('Waiting for provision state %(state)s on node %(node)s') % - {'state': wait_args['expected_state'], 'node': args.node}) - cc.node.wait_for_provision_state(args.node, timeout=args.wait_timeout, - **wait_args) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -def do_node_validate(cc, args): - """Validate a node's driver interfaces.""" - ifaces = cc.node.validate(args.node) - obj_list = [] - for key, value in ifaces.to_dict().items(): - data = {'interface': key} - data.update(value) - obj_list.append(type('iface', (object,), data)) - field_labels = ['Interface', 'Result', 'Reason'] - fields = ['interface', 'result', 'reason'] - cliutils.print_list(obj_list, fields, field_labels=field_labels, - json_flag=args.json) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -def do_node_get_console(cc, args): - """Get the connection information for a node's console, if enabled.""" - info = cc.node.get_console(args.node) - cliutils.print_dict(info, wrap=72, json_flag=args.json) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg( - 'enabled', - metavar='', - help="Enable or disable console access for a node: 'true' or 'false'.") -def do_node_set_console_mode(cc, args): - """Enable or disable serial console access for a node.""" - enable = utils.bool_argument_value("", args.enabled) - cc.node.set_console_mode(args.node, enable) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg( - 'device', - metavar='', - choices=v1_utils.BOOT_DEVICES, - help="One of %s." % ', '.join(v1_utils.BOOT_DEVICES)) -@cliutils.arg( - '--persistent', - dest='persistent', - action='store_true', - default=False, - help="Make changes persistent for all future boots.") -def do_node_set_boot_device(cc, args): - """Set the boot device for a node.""" - cc.node.set_boot_device(args.node, args.device, args.persistent) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -def do_node_get_boot_device(cc, args): - """Get the current boot device for a node.""" - boot_device = cc.node.get_boot_device(args.node) - cliutils.print_dict(boot_device, wrap=72, json_flag=args.json) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -def do_node_inject_nmi(cc, args): - """Inject NMI to a node.""" - cc.node.inject_nmi(args.node) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -def do_node_get_supported_boot_devices(cc, args): - """Get the supported boot devices for a node.""" - boot_devices = cc.node.get_supported_boot_devices(args.node) - boot_device_list = boot_devices.get('supported_boot_devices', []) - boot_devices['supported_boot_devices'] = ', '.join(boot_device_list) - cliutils.print_dict(boot_devices, wrap=72, json_flag=args.json) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -def do_node_show_states(cc, args): - """Show information about the node's states.""" - states = cc.node.states(args.node) - cliutils.print_dict(states.to_dict(), wrap=72, json_flag=args.json) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -def do_node_get_vendor_passthru_methods(cc, args): - """Get the vendor passthru methods for a node.""" - methods = cc.node.get_vendor_passthru_methods(args.node) - data = [] - for method, response in methods.items(): - response['name'] = method - http_methods = ','.join(response['http_methods']) - response['http_methods'] = http_methods - data.append(response) - fields = res_fields.VENDOR_PASSTHRU_METHOD_RESOURCE.fields - field_labels = res_fields.VENDOR_PASSTHRU_METHOD_RESOURCE.labels - cliutils.print_list(data, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -def do_node_vif_list(cc, args): - """List VIFs for a given node.""" - vifs = cc.node.vif_list(args.node) - fields = res_fields.VIF_RESOURCE.fields - field_labels = res_fields.VIF_RESOURCE.labels - cliutils.print_list(vifs, fields, field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg('vif_id', metavar='', - help="Name or UUID of the VIF to attach to node.") -@cliutils.arg('--vif-info', metavar='', - action='append', - help="Record arbitrary key/value metadata. " - "Can be specified multiple times. The mandatory 'id' " - "parameter cannot be specified as a key.") -def do_node_vif_attach(cc, args): - """Attach VIF to a given node.""" - fields = utils.key_value_pairs_to_dict(args.vif_info or []) - cc.node.vif_attach(args.node, args.vif_id, **fields) - - -@cliutils.arg('node', metavar='', help="Name or UUID of the node.") -@cliutils.arg('vif_id', metavar='', - help="Name or UUID of the VIF to detach from node.") -def do_node_vif_detach(cc, args): - """Detach VIF from a given node.""" - cc.node.vif_detach(args.node, args.vif_id) diff --git a/ironicclient/v1/port.py b/ironicclient/v1/port.py deleted file mode 100644 index 384a849..0000000 --- a/ironicclient/v1/port.py +++ /dev/null @@ -1,125 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2013 Red Hat, Inc -# -# 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 ironicclient.common import base -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc - - -class Port(base.Resource): - def __repr__(self): - return "" % self._info - - -class PortManager(base.CreateManager): - resource_class = Port - _creation_attributes = ['address', 'extra', 'local_link_connection', - 'node_uuid', 'physical_network', 'portgroup_uuid', - 'pxe_enabled', 'uuid'] - _resource_name = 'ports' - - def list(self, address=None, limit=None, marker=None, sort_key=None, - sort_dir=None, detail=False, fields=None, node=None, - portgroup=None): - """Retrieve a list of ports. - - :param address: Optional, MAC address of a port, to get - the port which has this MAC address - :param marker: Optional, the UUID of a port, eg the last - port from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of ports to return. - 2) limit == 0, return the entire list of ports. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about ports. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :param node: Optional, name or UUID of a node. Used to get - ports of this node. - - :param portgroup: Optional, name or UUID of a portgroup. Used to get - ports of this portgroup. - - :returns: A list of ports. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker, limit, sort_key, sort_dir, - fields) - if address is not None: - filters.append('address=%s' % address) - if node is not None: - filters.append('node=%s' % node) - if portgroup is not None: - filters.append('portgroup=%s' % portgroup) - - path = '' - if detail: - path += 'detail' - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "ports") - else: - return self._list_pagination(self._path(path), "ports", - limit=limit) - - def get(self, port_id, fields=None): - return self._get(resource_id=port_id, fields=fields) - - def get_by_address(self, address, fields=None): - path = '?address=%s' % address - if fields is not None: - path += '&fields=' + ','.join(fields) - else: - path = 'detail' + path - - ports = self._list(self._path(path), 'ports') - # get all the details of the port assuming that filtering by - # address returns a collection of one port if successful. - if len(ports) == 1: - return ports[0] - else: - raise exc.NotFound() - - def delete(self, port_id): - return self._delete(resource_id=port_id) - - def update(self, port_id, patch): - return self._update(resource_id=port_id, patch=patch) diff --git a/ironicclient/v1/port_shell.py b/ironicclient/v1/port_shell.py deleted file mode 100644 index e360b67..0000000 --- a/ironicclient/v1/port_shell.py +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright 2013 Red Hat, 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 ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient.v1 import resource_fields as res_fields - - -def _print_port_show(port, fields=None, json=False): - if fields is None: - fields = res_fields.PORT_DETAILED_RESOURCE.fields - - data = dict([(f, getattr(port, f, '')) for f in fields]) - cliutils.print_dict(data, wrap=72, json_flag=json) - - -@cliutils.arg( - 'port', - metavar='', - help="UUID of the port (or MAC address if --address is specified).") -@cliutils.arg( - '--address', - dest='address', - action='store_true', - default=False, - help=' is the MAC address (instead of the UUID) of the port.') -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more port fields. Only these fields will be fetched from " - "the server.") -def do_port_show(cc, args): - """Show detailed information about a port.""" - fields = args.fields[0] if args.fields else None - utils.check_for_invalid_fields( - fields, res_fields.PORT_DETAILED_RESOURCE.fields) - if args.address: - port = cc.port.get_by_address(args.port, fields=fields) - else: - utils.check_empty_arg(args.port, '') - port = cc.port.get(args.port, fields=fields) - _print_port_show(port, fields=fields, json=args.json) - - -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help="Show detailed information about ports.") -@cliutils.arg( - '--address', - metavar='', - help='Only show information for the port with this MAC address.') -@cliutils.arg( - '--limit', - metavar='', - type=int, - help='Maximum number of ports to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Ironic API Service.') -@cliutils.arg( - '--marker', - metavar='', - help='Port UUID (for example, of the last port in the list from a ' - 'previous request). Returns the list of ports after this UUID.') -@cliutils.arg( - '--sort-key', - metavar='', - help='Port field that will be used for sorting.') -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help='Sort direction: "asc" (the default) or "desc".') -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more port fields. Only these fields will be fetched from " - "the server. Can not be used when '--detail' is specified.") -def do_port_list(cc, args): - """List the ports.""" - params = {} - - if args.address is not None: - params['address'] = args.address - - if args.detail: - fields = res_fields.PORT_DETAILED_RESOURCE.fields - field_labels = res_fields.PORT_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], res_fields.PORT_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.PORT_RESOURCE.fields - field_labels = res_fields.PORT_RESOURCE.labels - - sort_fields = res_fields.PORT_DETAILED_RESOURCE.sort_fields - sort_field_labels = res_fields.PORT_DETAILED_RESOURCE.sort_labels - - params.update(utils.common_params_for_list(args, - sort_fields, - sort_field_labels)) - - port = cc.port.list(**params) - cliutils.print_list(port, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg( - '-a', '--address', - metavar='
', - required=True, - help='MAC address for this port.') -@cliutils.arg( - '-n', '--node', '--node_uuid', - dest='node_uuid', - metavar='', - required=True, - help='UUID of the node that this port belongs to.') -@cliutils.arg( - '-l', '--local-link-connection', - metavar="", - action='append', - help="Key/value metadata describing Local link connection information. " - "Valid keys are switch_info, switch_id, port_id." - "Can be specified multiple times.") -@cliutils.arg( - '--portgroup', - metavar="", - dest='portgroup_uuid', - help='UUID of the portgroup that this port belongs to.') -@cliutils.arg( - '--pxe-enabled', - metavar='', - help='Indicates whether this Port should be used when ' - 'PXE booting this Node.') -@cliutils.arg( - '--physical-network', - metavar='', - help="Physical network of the port.") -@cliutils.arg( - '-e', '--extra', - metavar="", - action='append', - help="Record arbitrary key/value metadata. " - "Can be specified multiple times.") -@cliutils.arg( - '-u', '--uuid', - metavar='', - help="UUID of the port.") -def do_port_create(cc, args): - """Create a new port.""" - field_list = ['address', 'extra', 'node_uuid', 'uuid', - 'local_link_connection', 'portgroup_uuid', - 'pxe_enabled', 'physical_network'] - fields = dict((k, v) for (k, v) in vars(args).items() - if k in field_list and not (v is None)) - fields = utils.args_array_to_dict(fields, 'extra') - fields = utils.args_array_to_dict(fields, 'local_link_connection') - port = cc.port.create(**fields) - - data = dict([(f, getattr(port, f, '')) for f in field_list]) - cliutils.print_dict(data, wrap=72, json_flag=args.json) - - -@cliutils.arg('port', metavar='', nargs='+', help="UUID of the port.") -def do_port_delete(cc, args): - """Delete a port.""" - failures = [] - for p in args.port: - try: - cc.port.delete(p) - print(_('Deleted port %s') % p) - except exceptions.ClientException as e: - failures.append(_("Failed to delete port %(port)s: %(error)s") - % {'port': p, 'error': e}) - if failures: - raise exceptions.ClientException("\n".join(failures)) - - -@cliutils.arg('port', metavar='', help="UUID of the port.") -@cliutils.arg( - 'op', - metavar='', - choices=['add', 'replace', 'remove'], - help="Operation: 'add', 'replace', or 'remove'.") -@cliutils.arg( - 'attributes', - metavar='', - nargs='+', - action='append', - default=[], - help="Attribute to add, replace, or remove. Can be specified multiple " - "times. For 'remove', only is necessary.") -def do_port_update(cc, args): - """Update information about a port.""" - patch = utils.args_array_to_patch(args.op, args.attributes[0]) - port = cc.port.update(args.port, patch) - _print_port_show(port, json=args.json) diff --git a/ironicclient/v1/portgroup.py b/ironicclient/v1/portgroup.py deleted file mode 100644 index c590ed0..0000000 --- a/ironicclient/v1/portgroup.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2016 SAP Ltd. -# -# 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 ironicclient.common import base -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc - - -class Portgroup(base.Resource): - def __repr__(self): - return "" % self._info - - -class PortgroupManager(base.CreateManager): - resource_class = Portgroup - _resource_name = 'portgroups' - _creation_attributes = ['address', 'extra', 'name', 'node_uuid', - 'standalone_ports_supported', 'mode', 'properties'] - - def list(self, node=None, address=None, limit=None, marker=None, - sort_key=None, sort_dir=None, detail=False, fields=None): - """Retrieve a list of portgroups. - - :param node: Optional, UUID or name of a node, to get - the portgroups for that node. - :param address: Optional, MAC address of a portgroup, to get - the portgroup which has this MAC address. - :param marker: Optional, the UUID of a portgroup, eg the last - portgroup from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of portgroups to return. - 2) limit == 0, return the entire list of portgroups. - 3) limit == None, the number of items returned respect the - maximum imposed by the Ironic API (see Ironic's - api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about portgroups. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: A list of portgroups. - :raises: InvalidAttribute if a subset of fields is requested with - detail option set. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker, limit, sort_key, sort_dir, - fields) - if address is not None: - filters.append('address=%s' % address) - if node is not None: - filters.append('node=%s' % node) - - path = '' - if detail: - path += 'detail' - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "portgroups") - else: - return self._list_pagination(self._path(path), "portgroups", - limit=limit) - - def list_ports(self, portgroup_id, marker=None, limit=None, sort_key=None, - sort_dir=None, detail=False, fields=None): - """List all the ports for a given portgroup. - - :param portgroup_id: Name or UUID of the portgroup. - :param marker: Optional, the UUID of a port, eg the last - port from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of ports to return. - 2) limit == 0, return the entire list of ports. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about ports. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: A list of ports. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker, limit, sort_key, sort_dir, - fields) - - path = "%s/ports" % portgroup_id - if detail: - path += '/detail' - - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "ports") - else: - return self._list_pagination(self._path(path), "ports", - limit=limit) - - def get(self, portgroup_id, fields=None): - """Get a port group with the specified identifier. - - :param portgroup_id: The UUID or name of a portgroup. - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: a :class:`Portgroup` object. - - """ - return self._get(resource_id=portgroup_id, fields=fields) - - def get_by_address(self, address, fields=None): - """Get a port group with the specified MAC address. - - :param address: The MAC address of a portgroup. - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: a :class:`Portgroup` object. - - """ - path = '?address=%s' % address - if fields is not None: - path += '&fields=' + ','.join(fields) - else: - path = 'detail' + path - - portgroups = self._list(self._path(path), 'portgroups') - # get all the details of the portgroup assuming that - # filtering by address returns a collection of one portgroup - # if successful. - if len(portgroups) == 1: - return portgroups[0] - else: - raise exc.NotFound() - - def delete(self, portgroup_id): - """Delete the Portgroup from the DB. - - :param portgroup_id: The UUID or name of a portgroup. - - """ - return self._delete(resource_id=portgroup_id) - - def update(self, portgroup_id, patch): - """Update the Portgroup. - - :param portgroup_id: The UUID or name of a portgroup. - :param patch: The patch request with updates. - - """ - return self._update(resource_id=portgroup_id, patch=patch) diff --git a/ironicclient/v1/portgroup_shell.py b/ironicclient/v1/portgroup_shell.py deleted file mode 100644 index 8e4f252..0000000 --- a/ironicclient/v1/portgroup_shell.py +++ /dev/null @@ -1,304 +0,0 @@ -# Copyright 2015 SAP Ltd. -# 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 ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient.v1 import resource_fields as res_fields - - -def _print_portgroup_show(portgroup, fields=None, json=False): - if fields is None: - fields = res_fields.PORTGROUP_DETAILED_RESOURCE.fields - - data = dict([(f, getattr(portgroup, f, '')) for f in fields]) - cliutils.print_dict(data, wrap=72, json_flag=json) - - -@cliutils.arg( - 'portgroup', - metavar='', - help="Name or UUID of the portgroup " - "(or MAC address if --address is specified).") -@cliutils.arg( - '--address', - dest='address', - action='store_true', - default=False, - help=' is the MAC address (instead of the UUID) of the portgroup.') -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more portgroup fields. Only these fields will be fetched " - "from the server.") -def do_portgroup_show(cc, args): - """Show detailed information about a portgroup.""" - fields = args.fields[0] if args.fields else None - utils.check_for_invalid_fields( - fields, res_fields.PORTGROUP_DETAILED_RESOURCE.fields) - if args.address: - portgroup = cc.portgroup.get_by_address(args.portgroup, fields=fields) - else: - utils.check_empty_arg(args.portgroup, '') - portgroup = cc.portgroup.get(args.portgroup, fields=fields) - _print_portgroup_show(portgroup, fields=fields, json=args.json) - - -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help="Show detailed information about portgroups.") -@cliutils.arg( - '-n', '--node', - dest='node', - metavar='', - help='UUID of the node that this portgroup belongs to.') -@cliutils.arg( - '-a', '--address', - metavar='', - help='Only show information for the portgroup with this MAC address.') -@cliutils.arg( - '--limit', - metavar='', - type=int, - help='Maximum number of portgroups to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Ironic API Service.') -@cliutils.arg( - '--marker', - metavar='', - help='Portgroup UUID (for example, of the last portgroup in the list ' - 'from a previous request). ' - 'Returns the list of portgroups after this UUID.') -@cliutils.arg( - '--sort-key', - metavar='', - help='Portgroup field that will be used for sorting.') -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help='Sort direction: "asc" (the default) or "desc".') -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more portgroup fields. Only these fields will be fetched " - "from the server. Can not be used when '--detail' is specified.") -def do_portgroup_list(cc, args): - """List the portgroups.""" - params = {} - - if args.address is not None: - params['address'] = args.address - if args.node is not None: - params['node'] = args.node - - if args.detail: - fields = res_fields.PORTGROUP_DETAILED_RESOURCE.fields - field_labels = res_fields.PORTGROUP_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], res_fields.PORTGROUP_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.PORTGROUP_RESOURCE.fields - field_labels = res_fields.PORTGROUP_RESOURCE.labels - - sort_fields = res_fields.PORTGROUP_DETAILED_RESOURCE.sort_fields - sort_field_labels = res_fields.PORTGROUP_DETAILED_RESOURCE.sort_labels - - params.update(utils.common_params_for_list(args, - sort_fields, - sort_field_labels)) - - portgroup = cc.portgroup.list(**params) - cliutils.print_list(portgroup, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg( - '-a', '--address', - metavar='
', - help='MAC address for this portgroup.') -@cliutils.arg( - '-n', '--node', - dest='node_uuid', - metavar='', - required=True, - help='UUID of the node that this portgroup belongs to.') -@cliutils.arg( - '--name', - metavar="", - help='Name for the portgroup.') -@cliutils.arg( - '-e', '--extra', - metavar="", - action='append', - help="Record arbitrary key/value metadata. " - "Can be specified multiple times.") -@cliutils.arg( - '--standalone-ports-supported', - metavar="", - help='Specifies whether ports from this portgroup can be used ' - 'in stand alone mode.') -@cliutils.arg( - '-u', '--uuid', - metavar='', - help="UUID of the portgroup.") -@cliutils.arg( - '-m', '--mode', - metavar='', - help="Portgroup mode. For possible values, refer to " - "https://www.kernel.org/doc/Documentation/networking/bonding.txt") -@cliutils.arg( - '-p', '--properties', - metavar="", - action='append', - help="Record key/value properties related to this portgroup's " - "configuration.") -def do_portgroup_create(cc, args): - """Create a new portgroup.""" - field_list = ['address', 'extra', 'node_uuid', 'name', 'uuid', - 'standalone_ports_supported', 'mode', 'properties'] - fields = dict((k, v) for (k, v) in vars(args).items() - if k in field_list and not (v is None)) - fields = utils.args_array_to_dict(fields, 'extra') - fields = utils.args_array_to_dict(fields, 'properties') - portgroup = cc.portgroup.create(**fields) - - data = dict([(f, getattr(portgroup, f, '')) for f in field_list]) - cliutils.print_dict(data, wrap=72, json_flag=args.json) - - -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help="Show detailed information about the ports.") -@cliutils.arg( - '--limit', - metavar='', - type=int, - help='Maximum number of ports to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Ironic API Service.') -@cliutils.arg( - '--marker', - metavar='', - help='Port UUID (for example, of the last port in the list from a ' - 'previous request). Returns the list of ports after this UUID.') -@cliutils.arg( - '--sort-key', - metavar='', - help='Port field that will be used for sorting.') -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help='Sort direction: "asc" (the default) or "desc".') -@cliutils.arg( - 'portgroup', - metavar='', - help="Name or UUID of the portgroup.") -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help="One or more port fields. Only these fields will be fetched from " - "the server. Can not be used when '--detail' is specified.") -def do_portgroup_port_list(cc, args): - """List the ports associated with a portgroup.""" - if args.detail: - fields = res_fields.PORT_DETAILED_RESOURCE.fields - field_labels = res_fields.PORT_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], res_fields.PORT_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.PORT_RESOURCE.fields - field_labels = res_fields.PORT_RESOURCE.labels - - sort_fields = res_fields.PORT_DETAILED_RESOURCE.sort_fields - sort_field_labels = res_fields.PORT_DETAILED_RESOURCE.sort_labels - - params = utils.common_params_for_list(args, sort_fields, - sort_field_labels) - - ports = cc.portgroup.list_ports(args.portgroup, **params) - - cliutils.print_list(ports, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg('portgroup', metavar='', nargs='+', - help="UUID or Name of the portgroup.") -def do_portgroup_delete(cc, args): - """Delete a portgroup.""" - failures = [] - for p in args.portgroup: - try: - cc.portgroup.delete(p) - print('Deleted portgroup %s' % p) - except exceptions.ClientException as e: - failures.append(_("Failed to delete portgroup %(pg)s: %(error)s") - % {'pg': p, 'error': e}) - if failures: - raise exceptions.ClientException("\n".join(failures)) - - -@cliutils.arg('portgroup', metavar='', - help="UUID or Name of the portgroup.") -@cliutils.arg( - 'op', - metavar='', - choices=['add', 'replace', 'remove'], - help="Operation: 'add', 'replace', or 'remove'.") -@cliutils.arg( - 'attributes', - metavar='', - nargs='+', - action='append', - default=[], - help="Attribute to add, replace, or remove. Can be specified multiple " - "times. For 'remove', only is necessary.") -def do_portgroup_update(cc, args): - """Update information about a portgroup.""" - patch = utils.args_array_to_patch(args.op, args.attributes[0]) - portgroup = cc.portgroup.update(args.portgroup, patch) - _print_portgroup_show(portgroup, json=args.json) diff --git a/ironicclient/v1/resource_fields.py b/ironicclient/v1/resource_fields.py deleted file mode 100644 index 8ff5ad8..0000000 --- a/ironicclient/v1/resource_fields.py +++ /dev/null @@ -1,411 +0,0 @@ -# Copyright 2014 Red Hat, 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 ironicclient.common.i18n import _ - - -class Resource(object): - """Resource class - - This class is used to manage the various fields that a resource (e.g. - Chassis, Node, Port) contains. An individual field consists of a - 'field_id' (key) and a 'label' (value). The caller only provides the - 'field_ids' when instantiating the object. - - Ordering of the 'field_ids' will be preserved as specified by the caller. - - It also provides the ability to exclude some of these fields when they are - being used for sorting. - """ - - FIELDS = { - 'address': 'Address', - 'async': 'Async', - 'attach': 'Response is attachment', - 'boot_index': 'Boot Index', - 'chassis_uuid': 'Chassis UUID', - 'clean_step': 'Clean Step', - 'console_enabled': 'Console Enabled', - 'created_at': 'Created At', - 'default_boot_interface': 'Default Boot Interface', - 'default_console_interface': 'Default Console Interface', - 'default_deploy_interface': 'Default Deploy Interface', - 'default_inspect_interface': 'Default Inspect Interface', - 'default_management_interface': 'Default Management Interface', - 'default_network_interface': 'Default Network Interface', - 'default_power_interface': 'Default Power Interface', - 'default_raid_interface': 'Default RAID Interface', - 'default_storage_interface': 'Default Storage Interface', - 'default_vendor_interface': 'Default Vendor Interface', - 'description': 'Description', - 'driver': 'Driver', - 'driver_info': 'Driver Info', - 'driver_internal_info': 'Driver Internal Info', - 'enabled_boot_interfaces': 'Enabled Boot Interfaces', - 'enabled_console_interfaces': 'Enabled Console Interfaces', - 'enabled_deploy_interfaces': 'Enabled Deploy Interfaces', - 'enabled_inspect_interfaces': 'Enabled Inspect Interfaces', - 'enabled_management_interfaces': 'Enabled Management Interfaces', - 'enabled_network_interfaces': 'Enabled Network Interfaces', - 'enabled_power_interfaces': 'Enabled Power Interfaces', - 'enabled_raid_interfaces': 'Enabled RAID Interfaces', - 'enabled_storage_interfaces': 'Enabled Storage Interfaces', - 'enabled_vendor_interfaces': 'Enabled Vendor Interfaces', - 'extra': 'Extra', - 'hosts': 'Active host(s)', - 'http_methods': 'Supported HTTP methods', - 'inspection_finished_at': 'Inspection Finished At', - 'inspection_started_at': 'Inspection Started At', - 'instance_info': 'Instance Info', - 'instance_uuid': 'Instance UUID', - 'internal_info': 'Internal Info', - 'last_error': 'Last Error', - 'maintenance': 'Maintenance', - 'maintenance_reason': 'Maintenance Reason', - 'mode': 'Mode', - 'name': 'Name', - 'node_uuid': 'Node UUID', - 'power_state': 'Power State', - 'properties': 'Properties', - 'provision_state': 'Provisioning State', - 'provision_updated_at': 'Provision Updated At', - 'raid_config': 'Current RAID configuration', - 'reservation': 'Reservation', - 'resource_class': 'Resource Class', - 'target_power_state': 'Target Power State', - 'target_provision_state': 'Target Provision State', - 'target_raid_config': 'Target RAID configuration', - 'type': 'Type', - 'updated_at': 'Updated At', - 'uuid': 'UUID', - 'volume_id': 'Volume ID', - 'volume_type': 'Driver Volume Type', - 'local_link_connection': 'Local Link Connection', - 'pxe_enabled': 'PXE boot enabled', - 'portgroup_uuid': 'Portgroup UUID', - 'boot_interface': 'Boot Interface', - 'console_interface': 'Console Interface', - 'deploy_interface': 'Deploy Interface', - 'inspect_interface': 'Inspect Interface', - 'management_interface': 'Management Interface', - 'network_interface': 'Network Interface', - 'power_interface': 'Power Interface', - 'raid_interface': 'RAID Interface', - 'storage_interface': 'Storage Interface', - 'vendor_interface': 'Vendor Interface', - 'standalone_ports_supported': 'Standalone Ports Supported', - 'physical_network': 'Physical Network', - 'id': 'ID', - 'connector_id': 'Connector ID', - } - - def __init__(self, field_ids, sort_excluded=None, override_labels=None): - """Create a Resource object - - :param field_ids: A list of strings that the Resource object will - contain. Each string must match an existing key in - FIELDS. - :param sort_excluded: Optional. A list of strings that will not be used - for sorting. Must be a subset of 'field_ids'. - :param override_labels: Optional. A dictionary, where key is a field ID - and value is the label to be used. If - unspecified, uses the labels associated with - the fields from global FIELDS. - - :raises: ValueError if sort_excluded or override_labels contains values - not in field_ids - """ - def check_param_fields(param_name, param_fields): - not_existing = set(param_fields) - set(field_ids) - if not_existing: - raise ValueError( - _("%(param)s specified with value not contained in " - "field_ids. Unknown value(s): %(unknown)s") - % {'param': param_name, - 'unknown': ', '.join(not_existing)}) - - if override_labels is None: - override_labels = {} - else: - check_param_fields('override_labels', override_labels.keys()) - - self._fields = tuple(field_ids) - self._labels = tuple([override_labels.get(x) or self.FIELDS[x] - for x in field_ids]) - - if sort_excluded is None: - sort_excluded = [] - else: - check_param_fields('sort_excluded', sort_excluded) - self._sort_fields = tuple( - [x for x in field_ids if x not in sort_excluded]) - self._sort_labels = tuple([override_labels.get(x) or self.FIELDS[x] - for x in self._sort_fields]) - - @property - def fields(self): - return self._fields - - @property - def labels(self): - return self._labels - - @property - def sort_fields(self): - return self._sort_fields - - @property - def sort_labels(self): - return self._sort_labels - - -# Chassis -CHASSIS_DETAILED_RESOURCE = Resource( - ['uuid', - 'description', - 'created_at', - 'updated_at', - 'extra', - ], - sort_excluded=['extra']) -CHASSIS_RESOURCE = Resource( - ['uuid', - 'description', - ]) - -# Nodes -NODE_DETAILED_RESOURCE = Resource( - ['chassis_uuid', - 'created_at', - 'clean_step', - 'console_enabled', - 'driver', - 'driver_info', - 'driver_internal_info', - 'extra', - 'instance_info', - 'instance_uuid', - 'last_error', - 'maintenance', - 'maintenance_reason', - 'power_state', - 'properties', - 'provision_state', - 'provision_updated_at', - 'raid_config', - 'reservation', - 'resource_class', - 'target_power_state', - 'target_provision_state', - 'target_raid_config', - 'updated_at', - 'inspection_finished_at', - 'inspection_started_at', - 'uuid', - 'name', - 'boot_interface', - 'console_interface', - 'deploy_interface', - 'inspect_interface', - 'management_interface', - 'network_interface', - 'power_interface', - 'raid_interface', - 'storage_interface', - 'vendor_interface', - ], - sort_excluded=[ - # The server cannot sort on "chassis_uuid" because it isn't a column in - # the "nodes" database table. "chassis_id" is stored, but it is - # internal to ironic. See bug #1443003 for more details. - 'chassis_uuid', - 'clean_step', - 'driver_info', - 'driver_internal_info', - 'extra', - 'instance_info', - 'properties', - 'raid_config', - 'target_raid_config', - ]) -NODE_RESOURCE = Resource( - ['uuid', - 'name', - 'instance_uuid', - 'power_state', - 'provision_state', - 'maintenance', - ]) -VENDOR_PASSTHRU_METHOD_RESOURCE = Resource( - ['name', - 'http_methods', - 'async', - 'description', - 'attach' - ]) - -# Ports -PORT_DETAILED_RESOURCE = Resource( - ['uuid', - 'address', - 'created_at', - 'extra', - 'node_uuid', - 'local_link_connection', - 'portgroup_uuid', - 'pxe_enabled', - 'physical_network', - 'updated_at', - 'internal_info', - ], - sort_excluded=[ - 'extra', - # The server cannot sort on "node_uuid" or "portgroup_uuid" because - # they aren't columns in the "ports" database table. "node_id" and - # "portgroup_id" are stored, but it is internal to ironic. - # See bug #1443003 for more details. - 'node_uuid', - 'portgroup_uuid', - 'internal_info', - ]) -PORT_RESOURCE = Resource( - ['uuid', - 'address', - ]) - -# Portgroups -PORTGROUP_DETAILED_RESOURCE = Resource( - ['uuid', - 'address', - 'created_at', - 'extra', - 'standalone_ports_supported', - 'node_uuid', - 'name', - 'updated_at', - 'internal_info', - 'mode', - 'properties', - ], - sort_excluded=[ - 'extra', - # The server cannot sort on "node_uuid" because it isn't a column in - # the "portgroups" database table. "node_id" is stored, but it is - # internal to ironic. See bug #1443003 for more details. - 'node_uuid', - 'internal_info', - 'properties', - ]) -PORTGROUP_RESOURCE = Resource( - ['uuid', - 'address', - 'name', - ]) - -# VIFs -VIF_RESOURCE = Resource( - ['id'], -) - -# Drivers -DRIVER_DETAILED_RESOURCE = Resource( - ['name', - 'type', - 'hosts', - 'default_boot_interface', - 'default_console_interface', - 'default_deploy_interface', - 'default_inspect_interface', - 'default_management_interface', - 'default_network_interface', - 'default_power_interface', - 'default_raid_interface', - 'default_storage_interface', - 'default_vendor_interface', - 'enabled_boot_interfaces', - 'enabled_console_interfaces', - 'enabled_deploy_interfaces', - 'enabled_inspect_interfaces', - 'enabled_management_interfaces', - 'enabled_network_interfaces', - 'enabled_power_interfaces', - 'enabled_raid_interfaces', - 'enabled_storage_interfaces', - 'enabled_vendor_interfaces' - ], - override_labels={'name': 'Supported driver(s)'} -) -DRIVER_RESOURCE = Resource( - ['name', - 'hosts', - ], - override_labels={'name': 'Supported driver(s)'} -) - -# Volume connectors -VOLUME_CONNECTOR_DETAILED_RESOURCE = Resource( - ['uuid', - 'node_uuid', - 'type', - 'connector_id', - 'extra', - 'created_at', - 'updated_at', - ], - sort_excluded=[ - # The server cannot sort on "node_uuid" because it isn't a column in - # the "volume_connectors" database table. "node_id" is stored, but it - # is internal to ironic. See bug #1443003 for more details. - 'node_uuid', - 'extra', - ]) -VOLUME_CONNECTOR_RESOURCE = Resource( - ['uuid', - 'node_uuid', - 'type', - 'connector_id', - ], - sort_excluded=['node_uuid'] -) - -# Volume targets -VOLUME_TARGET_DETAILED_RESOURCE = Resource( - ['uuid', - 'node_uuid', - 'volume_type', - 'properties', - 'boot_index', - 'extra', - 'volume_id', - 'created_at', - 'updated_at', - ], - sort_excluded=[ - # The server cannot sort on "node_uuid" because it isn't a column in - # the "volume_targets" database table. "node_id" is stored, but it - # is internal to ironic. See bug #1443003 for more details. - 'node_uuid', - 'extra', - 'properties' - ]) -VOLUME_TARGET_RESOURCE = Resource( - ['uuid', - 'node_uuid', - 'volume_type', - 'boot_index', - 'volume_id', - ], - sort_excluded=['node_uuid'] -) diff --git a/ironicclient/v1/shell.py b/ironicclient/v1/shell.py deleted file mode 100644 index a31422f..0000000 --- a/ironicclient/v1/shell.py +++ /dev/null @@ -1,48 +0,0 @@ -# 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 ironicclient.common import utils -from ironicclient.v1 import chassis_shell -from ironicclient.v1 import create_resources_shell -from ironicclient.v1 import driver_shell -from ironicclient.v1 import node_shell -from ironicclient.v1 import port_shell -from ironicclient.v1 import portgroup_shell -from ironicclient.v1 import volume_connector_shell -from ironicclient.v1 import volume_target_shell - -COMMAND_MODULES = [ - chassis_shell, - node_shell, - port_shell, - portgroup_shell, - driver_shell, - create_resources_shell, - volume_connector_shell, - volume_target_shell, -] - - -def enhance_parser(parser, subparsers, cmd_mapper): - """Enhance parser with API version specific options. - - Take a basic (nonversioned) parser and enhance it with - commands and options specific for this version of API. - - :param parser: top level parser - :param subparsers: top level parser's subparsers collection - where subcommands will go - """ - for command_module in COMMAND_MODULES: - utils.define_commands_from_module(subparsers, command_module, - cmd_mapper) diff --git a/ironicclient/v1/utils.py b/ironicclient/v1/utils.py deleted file mode 100644 index 7c18e60..0000000 --- a/ironicclient/v1/utils.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2016 Intel Corporation -# 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. - -HTTP_METHODS = ['POST', 'PUT', 'GET', 'DELETE', 'PATCH'] - -BOOT_DEVICES = ['pxe', 'disk', 'cdrom', 'bios', 'safe'] - -# Polling intervals in seconds. -_LONG_ACTION_POLL_INTERVAL = 10 -_SHORT_ACTION_POLL_INTERVAL = 2 -# This dict acts as both list of possible provision actions and arguments for -# wait_for_provision_state invocation. -PROVISION_ACTIONS = { - 'active': {'expected_state': 'active', - 'poll_interval': _LONG_ACTION_POLL_INTERVAL}, - 'deleted': {'expected_state': 'available', - 'poll_interval': _LONG_ACTION_POLL_INTERVAL}, - 'rebuild': {'expected_state': 'active', - 'poll_interval': _LONG_ACTION_POLL_INTERVAL}, - 'inspect': {'expected_state': 'manageable', - # This is suboptimal for in-band inspection, but it's probably - # not worth making people wait 10 seconds for OOB inspection - 'poll_interval': _SHORT_ACTION_POLL_INTERVAL}, - 'provide': {'expected_state': 'available', - # This assumes cleaning is in place - 'poll_interval': _LONG_ACTION_POLL_INTERVAL}, - 'manage': {'expected_state': 'manageable', - 'poll_interval': _SHORT_ACTION_POLL_INTERVAL}, - 'clean': {'expected_state': 'manageable', - 'poll_interval': _LONG_ACTION_POLL_INTERVAL}, - 'adopt': {'expected_state': 'active', - 'poll_interval': _SHORT_ACTION_POLL_INTERVAL}, - 'abort': None, # no support for --wait in abort -} - -PROVISION_STATES = list(PROVISION_ACTIONS) diff --git a/ironicclient/v1/volume_connector.py b/ironicclient/v1/volume_connector.py deleted file mode 100644 index f1c9d96..0000000 --- a/ironicclient/v1/volume_connector.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2015 Hitachi Data Systems -# -# 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 ironicclient.common import base -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc - - -class VolumeConnector(base.Resource): - def __repr__(self): - return "" % self._info - - -class VolumeConnectorManager(base.CreateManager): - resource_class = VolumeConnector - _creation_attributes = ['extra', 'node_uuid', 'type', 'connector_id', - 'uuid'] - _resource_name = 'volume/connectors' - - def list(self, node=None, limit=None, marker=None, sort_key=None, - sort_dir=None, detail=False, fields=None): - """Retrieve a list of volume connector. - - :param node: Optional, UUID or name of a node, to get volume - connectors for this node only. - :param marker: Optional, the UUID of a volume connector, eg the last - volume connector from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of volume connectors to return. - 2) limit == 0, return the entire list of volume connectors. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about volume connectors. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: A list of volume connectors. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker=marker, limit=limit, - sort_key=sort_key, sort_dir=sort_dir, - fields=fields, detail=detail) - if node is not None: - filters.append('node=%s' % node) - - path = '' - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "connectors") - else: - return self._list_pagination(self._path(path), "connectors", - limit=limit) - - def get(self, volume_connector_id, fields=None): - return self._get(resource_id=volume_connector_id, fields=fields) - - def delete(self, volume_connector_id): - return self._delete(resource_id=volume_connector_id) - - def update(self, volume_connector_id, patch): - return self._update(resource_id=volume_connector_id, patch=patch) diff --git a/ironicclient/v1/volume_connector_shell.py b/ironicclient/v1/volume_connector_shell.py deleted file mode 100644 index c6d3fa0..0000000 --- a/ironicclient/v1/volume_connector_shell.py +++ /dev/null @@ -1,209 +0,0 @@ -# Copyright 2017 Hitachi Data Systems -# -# 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 ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient.v1 import resource_fields as res_fields - - -def _print_volume_connector_show(volume_connector, fields=None, json=False): - if fields is None: - fields = res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.fields - - data = dict([(f, getattr(volume_connector, f, '')) for f in fields]) - cliutils.print_dict(data, wrap=72, json_flag=json) - - -@cliutils.arg( - 'volume_connector', - metavar='', - help=_("UUID of the volume connector.")) -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help=_("One or more volume connector fields. Only these fields will be " - "fetched from the server.")) -def do_volume_connector_show(cc, args): - """Show detailed information about a volume connector.""" - fields = args.fields[0] if args.fields else None - utils.check_for_invalid_fields( - fields, res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.fields) - utils.check_empty_arg(args.volume_connector, '') - volume_connector = cc.volume_connector.get(args.volume_connector, - fields=fields) - _print_volume_connector_show(volume_connector, fields=fields, - json=args.json) - - -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help=_("Show detailed information about volume connectors.")) -@cliutils.arg( - '-n', '--node', - metavar='', - help=_('Only list volume connectors of this node (name or UUID)')) -@cliutils.arg( - '--limit', - metavar='', - type=int, - help=_('Maximum number of volume connectors to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Baremetal API Service.')) -@cliutils.arg( - '--marker', - metavar='', - help=_('Volume connector UUID (for example, of the last volume connector ' - 'in the list from a previous request). Returns the list of volume ' - 'connectors after this UUID.')) -@cliutils.arg( - '--sort-key', - metavar='', - help=_('Volume connector field that will be used for sorting.')) -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help=_('Sort direction: "asc" (the default) or "desc".')) -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help=_("One or more volume connector fields. Only these fields will be " - "fetched from the server. Can not be used when '--detail' is " - "specified.")) -def do_volume_connector_list(cc, args): - """List the volume connectors.""" - params = {} - - if args.node is not None: - params['node'] = args.node - - if args.detail: - fields = res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.fields - field_labels = res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], - res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.VOLUME_CONNECTOR_RESOURCE.fields - field_labels = res_fields.VOLUME_CONNECTOR_RESOURCE.labels - - sort_fields = res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.sort_fields - sort_field_labels = ( - res_fields.VOLUME_CONNECTOR_DETAILED_RESOURCE.sort_labels) - - params.update(utils.common_params_for_list(args, - sort_fields, - sort_field_labels)) - - volume_connector = cc.volume_connector.list(**params) - cliutils.print_list(volume_connector, fields, - field_labels=field_labels, - sortby_index=None, - json_flag=args.json) - - -@cliutils.arg( - '-e', '--extra', - metavar="", - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.")) -@cliutils.arg( - '-n', '--node', - dest='node_uuid', - metavar='', - required=True, - help=_('UUID of the node that this volume connector belongs to.')) -@cliutils.arg( - '-t', '--type', - metavar="", - required=True, - choices=['iqn', 'ip', 'mac', 'wwnn', 'wwpn'], - help=_("Type of the volume connector. Can be 'iqn', 'ip', 'mac', 'wwnn', " - "'wwpn'.")) -@cliutils.arg( - '-i', '--connector_id', - metavar="", - required=True, - help=_("ID of the Volume connector in the specified type.")) -@cliutils.arg( - '-u', '--uuid', - metavar='', - help=_("UUID of the volume connector.")) -def do_volume_connector_create(cc, args): - """Create a new volume connector.""" - field_list = ['extra', 'type', 'connector_id', 'node_uuid', 'uuid'] - fields = dict((k, v) for (k, v) in vars(args).items() - if k in field_list and not (v is None)) - fields = utils.args_array_to_dict(fields, 'extra') - volume_connector = cc.volume_connector.create(**fields) - - data = dict([(f, getattr(volume_connector, f, '')) for f in field_list]) - cliutils.print_dict(data, wrap=72, json_flag=args.json) - - -@cliutils.arg('volume_connector', metavar='', nargs='+', - help=_("UUID of the volume connector.")) -def do_volume_connector_delete(cc, args): - """Delete a volume connector.""" - failures = [] - for vc in args.volume_connector: - try: - cc.volume_connector.delete(vc) - print(_('Deleted volume connector %s') % vc) - except exceptions.ClientException as e: - failures.append(_("Failed to delete volume connector %(vc)s: " - "%(error)s") - % {'vc': vc, 'error': e}) - if failures: - raise exceptions.ClientException("\n".join(failures)) - - -@cliutils.arg('volume_connector', metavar='', - help=_("UUID of the volume connector.")) -@cliutils.arg( - 'op', - metavar='', - choices=['add', 'replace', 'remove'], - help=_("Operation: 'add', 'replace', or 'remove'.")) -@cliutils.arg( - 'attributes', - metavar='', - nargs='+', - action='append', - default=[], - help=_("Attribute to add, replace, or remove. Can be specified multiple " - "times. For 'remove', only is necessary.")) -def do_volume_connector_update(cc, args): - """Update information about a volume connector.""" - patch = utils.args_array_to_patch(args.op, args.attributes[0]) - volume_connector = cc.volume_connector.update(args.volume_connector, patch) - _print_volume_connector_show(volume_connector, json=args.json) diff --git a/ironicclient/v1/volume_target.py b/ironicclient/v1/volume_target.py deleted file mode 100644 index 7a7bf50..0000000 --- a/ironicclient/v1/volume_target.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2016 Hitachi, Ltd. -# -# 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 ironicclient.common import base -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient import exc - - -class VolumeTarget(base.Resource): - def __repr__(self): - return "" % self._info - - -class VolumeTargetManager(base.CreateManager): - resource_class = VolumeTarget - _creation_attributes = ['extra', 'node_uuid', 'volume_type', - 'properties', 'boot_index', 'volume_id', - 'uuid'] - _resource_name = 'volume/targets' - - def list(self, node=None, limit=None, marker=None, sort_key=None, - sort_dir=None, detail=False, fields=None): - """Retrieve a list of volume target. - - :param node: Optional, UUID or name of a node, to get volume - targets for this node only. - :param marker: Optional, the UUID of a volume target, eg the last - volume target from a previous result set. Return - the next result set. - :param limit: The maximum number of results to return per - request, if: - - 1) limit > 0, the maximum number of volume targets to return. - 2) limit == 0, return the entire list of volume targets. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Ironic API - (see Ironic's api.max_limit option). - - :param sort_key: Optional, field used for sorting. - - :param sort_dir: Optional, direction of sorting, either 'asc' (the - default) or 'desc'. - - :param detail: Optional, boolean whether to return detailed information - about volume targets. - - :param fields: Optional, a list with a specified set of fields - of the resource to be returned. Can not be used - when 'detail' is set. - - :returns: A list of volume targets. - - """ - if limit is not None: - limit = int(limit) - - if detail and fields: - raise exc.InvalidAttribute(_("Can't fetch a subset of fields " - "with 'detail' set")) - - filters = utils.common_filters(marker=marker, limit=limit, - sort_key=sort_key, sort_dir=sort_dir, - fields=fields, detail=detail) - if node is not None: - filters.append('node=%s' % node) - - path = '' - if filters: - path += '?' + '&'.join(filters) - - if limit is None: - return self._list(self._path(path), "targets") - else: - return self._list_pagination(self._path(path), "targets", - limit=limit) - - def get(self, volume_target_id, fields=None): - return self._get(resource_id=volume_target_id, fields=fields) - - def delete(self, volume_target_id): - return self._delete(resource_id=volume_target_id) - - def update(self, volume_target_id, patch): - return self._update(resource_id=volume_target_id, patch=patch) diff --git a/ironicclient/v1/volume_target_shell.py b/ironicclient/v1/volume_target_shell.py deleted file mode 100644 index 4d145e6..0000000 --- a/ironicclient/v1/volume_target_shell.py +++ /dev/null @@ -1,216 +0,0 @@ -# Copyright 2017 Hitachi, Ltd. -# -# 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 ironicclient.common.apiclient import exceptions -from ironicclient.common import cliutils -from ironicclient.common.i18n import _ -from ironicclient.common import utils -from ironicclient.v1 import resource_fields as res_fields - - -def _print_volume_target_show(volume_target, fields=None, json=False): - if fields is None: - fields = res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields - - data = dict([(f, getattr(volume_target, f, '')) for f in fields]) - cliutils.print_dict(data, wrap=72, json_flag=json) - - -@cliutils.arg( - 'volume_target', - metavar='', - help=_("UUID of the volume target.")) -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help=_("One or more volume target fields. Only these fields will be " - "fetched from the server.")) -def do_volume_target_show(cc, args): - """Show detailed information about a volume target.""" - fields = args.fields[0] if args.fields else None - utils.check_for_invalid_fields( - fields, res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields) - utils.check_empty_arg(args.volume_target, '') - volume_target = cc.volume_target.get(args.volume_target, fields=fields) - _print_volume_target_show(volume_target, fields=fields, json=args.json) - - -@cliutils.arg( - '--detail', - dest='detail', - action='store_true', - default=False, - help=_("Show detailed information about volume targets.")) -@cliutils.arg( - '-n', '--node', - metavar='', - help=_('Only list volume targets of this node (name or UUID)')) -@cliutils.arg( - '--limit', - metavar='', - type=int, - help=_('Maximum number of volume targets to return per request, ' - '0 for no limit. Default is the maximum number used ' - 'by the Baremetal API Service.')) -@cliutils.arg( - '--marker', - metavar='', - help=_('Volume target UUID (for example, of the last volume target in ' - 'the list from a previous request). Returns the list of volume ' - 'targets after this UUID.')) -@cliutils.arg( - '--sort-key', - metavar='', - help=_('Volume target field that will be used for sorting.')) -@cliutils.arg( - '--sort-dir', - metavar='', - choices=['asc', 'desc'], - help=_('Sort direction: "asc" (the default) or "desc".')) -@cliutils.arg( - '--fields', - nargs='+', - dest='fields', - metavar='', - action='append', - default=[], - help=_("One or more volume target fields. Only these fields will be " - "fetched from the server. Can not be used when '--detail' is " - "specified.")) -def do_volume_target_list(cc, args): - """List the volume targets.""" - params = {} - - if args.node is not None: - params['node'] = args.node - - if args.detail: - fields = res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields - field_labels = res_fields.VOLUME_TARGET_DETAILED_RESOURCE.labels - elif args.fields: - utils.check_for_invalid_fields( - args.fields[0], - res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields) - resource = res_fields.Resource(args.fields[0]) - fields = resource.fields - field_labels = resource.labels - else: - fields = res_fields.VOLUME_TARGET_RESOURCE.fields - field_labels = res_fields.VOLUME_TARGET_RESOURCE.labels - - sort_fields = res_fields.VOLUME_TARGET_DETAILED_RESOURCE.sort_fields - sort_field_labels = ( - res_fields.VOLUME_TARGET_DETAILED_RESOURCE.sort_labels) - - params.update(utils.common_params_for_list(args, - sort_fields, - sort_field_labels)) - - volume_target = cc.volume_target.list(**params) - cliutils.print_list(volume_target, fields, field_labels=field_labels, - sortby_index=None, json_flag=args.json) - - -@cliutils.arg( - '-e', '--extra', - metavar="", - action='append', - help=_("Record arbitrary key/value metadata. " - "Can be specified multiple times.")) -@cliutils.arg( - '-n', '--node', - dest='node_uuid', - metavar='', - required=True, - help=_('UUID of the node that this volume target belongs to.')) -@cliutils.arg( - '-t', '--type', - metavar="", - required=True, - help=_("Type of the volume target, e.g. 'iscsi', 'fibre_channel', 'rbd'.")) -@cliutils.arg( - '-p', '--properties', - metavar="", - action='append', - help=_("Key/value property related to the type of this volume " - "target. Can be specified multiple times.")) -@cliutils.arg( - '-b', '--boot-index', - metavar="", - required=True, - help=_("Boot index of the volume target.")) -@cliutils.arg( - '-i', '--volume_id', - metavar="", - required=True, - help=_("ID of the volume associated with this target.")) -@cliutils.arg( - '-u', '--uuid', - metavar='', - help=_("UUID of the volume target.")) -def do_volume_target_create(cc, args): - """Create a new volume target.""" - field_list = ['extra', 'volume_type', 'properties', - 'boot_index', 'node_uuid', 'volume_id', 'uuid'] - fields = dict((k, v) for (k, v) in vars(args).items() - if k in field_list and not (v is None)) - fields = utils.args_array_to_dict(fields, 'properties') - fields = utils.args_array_to_dict(fields, 'extra') - volume_target = cc.volume_target.create(**fields) - - data = dict([(f, getattr(volume_target, f, '')) for f in field_list]) - cliutils.print_dict(data, wrap=72, json_flag=args.json) - - -@cliutils.arg('volume_target', metavar='', nargs='+', - help=_("UUID of the volume target.")) -def do_volume_target_delete(cc, args): - """Delete a volume target.""" - failures = [] - for vt in args.volume_target: - try: - cc.volume_target.delete(vt) - print(_('Deleted volume target %s') % vt) - except exceptions.ClientException as e: - failures.append(_("Failed to delete volume target %(vt)s: " - "%(error)s") - % {'vt': vt, 'error': e}) - if failures: - raise exceptions.ClientException("\n".join(failures)) - - -@cliutils.arg('volume_target', metavar='', - help=_("UUID of the volume target.")) -@cliutils.arg( - 'op', - metavar='', - choices=['add', 'replace', 'remove'], - help=_("Operation: 'add', 'replace', or 'remove'.")) -@cliutils.arg( - 'attributes', - metavar='', - nargs='+', - action='append', - default=[], - help=_("Attribute to add, replace, or remove. Can be specified multiple " - "times. For 'remove', only is necessary.")) -def do_volume_target_update(cc, args): - """Update information about a volume target.""" - patch = utils.args_array_to_patch(args.op, args.attributes[0]) - volume_target = cc.volume_target.update(args.volume_target, patch) - _print_volume_target_show(volume_target, json=args.json) diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/notes/SHA1-hash-auth-token-f8dce46f854c002c.yaml b/releasenotes/notes/SHA1-hash-auth-token-f8dce46f854c002c.yaml deleted file mode 100644 index c8d13ef..0000000 --- a/releasenotes/notes/SHA1-hash-auth-token-f8dce46f854c002c.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -other: - - Log the SHA1 hash of X-Auth-Token value prefixed - by '{SHA}'. diff --git a/releasenotes/notes/add-chassis_uuid-removal-possibility-5bc0bc3a7953eaa5.yaml b/releasenotes/notes/add-chassis_uuid-removal-possibility-5bc0bc3a7953eaa5.yaml deleted file mode 100644 index 4286bbc..0000000 --- a/releasenotes/notes/add-chassis_uuid-removal-possibility-5bc0bc3a7953eaa5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Add possibility to remove chassis_uuid for node by adding - '--chassis-uuid' argument to 'openstack baremetal node unset' - command. diff --git a/releasenotes/notes/add-create-command-3df5efbbecc33276.yaml b/releasenotes/notes/add-create-command-3df5efbbecc33276.yaml deleted file mode 100644 index 4878907..0000000 --- a/releasenotes/notes/add-create-command-3df5efbbecc33276.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - Adds a new ``ironic create`` command that creates resources (chassis, - nodes, ports) specified in one or more JSON (``*.json``) or YAML - (``*.yaml``) files. - - Adds a new ``openstack baremetal create`` command. Similar to the ``ironic - create`` command, this command creates resources specified in one or more - files. (Note that ``openstack baremetal create`` can also be used to create - a node via specified node attributes. However, this feature has been - deprecated since 1.4.0.) diff --git a/releasenotes/notes/add-environment-variable-to-specify-version-cache-timeout-dfa5f6d4af0ea1d3.yaml b/releasenotes/notes/add-environment-variable-to-specify-version-cache-timeout-dfa5f6d4af0ea1d3.yaml deleted file mode 100644 index 36a6beb..0000000 --- a/releasenotes/notes/add-environment-variable-to-specify-version-cache-timeout-dfa5f6d4af0ea1d3.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Add support for specifying the expiry (in seconds) of the caching - of the ironic API version, via the environment variable - "IRONICCLIENT_CACHE_EXPIRY". diff --git a/releasenotes/notes/add-json-option-0cf29be2a97e0212.yaml b/releasenotes/notes/add-json-option-0cf29be2a97e0212.yaml deleted file mode 100644 index 1de9ea1..0000000 --- a/releasenotes/notes/add-json-option-0cf29be2a97e0212.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Add a --json option to the client to display the JSON - response body from the Ironic API without formatting it. diff --git a/releasenotes/notes/add-neutron-integration-fields-cee7596c49722de6.yaml b/releasenotes/notes/add-neutron-integration-fields-cee7596c49722de6.yaml deleted file mode 100644 index e78de13..0000000 --- a/releasenotes/notes/add-neutron-integration-fields-cee7596c49722de6.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -features: - - | - Add support of new fields: - - * ``node.network_interface`` is introduced in API 1.20, - specifies the network interface to use for a node. - * ``port.local_link_connection`` contains the port binding - profile. - * ``port.pxe_enabled`` indicates whether PXE is enabled - for the port. - - The ``port.local_link_connection`` and ``port.pxe_enabled`` fields - were introduced in API 1.19. diff --git a/releasenotes/notes/add-node-resource-class-6040d1d6c734522c.yaml b/releasenotes/notes/add-node-resource-class-6040d1d6c734522c.yaml deleted file mode 100644 index ead301f..0000000 --- a/releasenotes/notes/add-node-resource-class-6040d1d6c734522c.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Adds support for the new ``node.resource_class`` field, - which was introduced in API version 1.21. diff --git a/releasenotes/notes/add-pecan-exc-construction-a776408f7ae110dc.yaml b/releasenotes/notes/add-pecan-exc-construction-a776408f7ae110dc.yaml deleted file mode 100644 index ad8ff0c..0000000 --- a/releasenotes/notes/add-pecan-exc-construction-a776408f7ae110dc.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -fixes: - - Fixes an issue where certain error messages from the - ironic API were suppressed. diff --git a/releasenotes/notes/add-port-internal-info-74a03ebd8b0a3dfc.yaml b/releasenotes/notes/add-port-internal-info-74a03ebd8b0a3dfc.yaml deleted file mode 100644 index b6e3007..0000000 --- a/releasenotes/notes/add-port-internal-info-74a03ebd8b0a3dfc.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - The ``ironic port-show``, ``ironic port-list --detail``, and ``ironic - node-port-list --detail`` commands now include the ``internal_info`` field - in the output. diff --git a/releasenotes/notes/add-portgroup-mode-properties-0a3023cf905adaef.yaml b/releasenotes/notes/add-portgroup-mode-properties-0a3023cf905adaef.yaml deleted file mode 100644 index 029961b..0000000 --- a/releasenotes/notes/add-portgroup-mode-properties-0a3023cf905adaef.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Mode and properties fields were added to the portgroup object, along with - respective arguments for the ironic CLI and the OpenStackClient plugin, - they are available starting with ironic API microversion 1.26. diff --git a/releasenotes/notes/add-portgroups-support-c3cf3826093ee815.yaml b/releasenotes/notes/add-portgroups-support-c3cf3826093ee815.yaml deleted file mode 100644 index 20b64c9..0000000 --- a/releasenotes/notes/add-portgroups-support-c3cf3826093ee815.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -features: - - | - Extends the Ironic CLI with new commands: - - * ironic portgroup-create - * ironic portgroup-show - * ironic portgroup-list - * ironic portgroup-delete - * ironic portgroup-update - * ironic portgroup-port-list - - Also extends ironic port-create with --portgroup. - Portgroup support was added in Ironic API version 1.24. diff --git a/releasenotes/notes/add-portgroups-to-create-command-6d685277f7af79df.yaml b/releasenotes/notes/add-portgroups-to-create-command-6d685277f7af79df.yaml deleted file mode 100644 index 8782c89..0000000 --- a/releasenotes/notes/add-portgroups-to-create-command-6d685277f7af79df.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Supports creation of port groups via ``ironic create`` and - ``openstack baremetal create`` commands. - diff --git a/releasenotes/notes/add-vif-attach-detach-support-e680d64e4add0fa4.yaml b/releasenotes/notes/add-vif-attach-detach-support-e680d64e4add0fa4.yaml deleted file mode 100644 index 6df49f6..0000000 --- a/releasenotes/notes/add-vif-attach-detach-support-e680d64e4add0fa4.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -features: - - | - Adds support for attaching and detaching VIFs. This is available starting - with ironic API microversion 1.28. - - The new commands are: - - * ``ironic node-vif-list `` - * ``ironic node-vif-attach `` - * ``ironic node-vif-detach `` - * ``openstack baremetal node vif list `` - * ``openstack baremetal node vif attach `` - * ``openstack baremetal node vif detach `` diff --git a/releasenotes/notes/add-volume-connector-api-873090474d5e41b8.yaml b/releasenotes/notes/add-volume-connector-api-873090474d5e41b8.yaml deleted file mode 100644 index 45d05c5..0000000 --- a/releasenotes/notes/add-volume-connector-api-873090474d5e41b8.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -features: - - | - Adds these python API client methods to support volume connector resources - (available starting with API version 1.32): - - * ``client.volume_connector.create`` for creating a volume connector - * ``client.volume_connector.list`` for listing volume connectors - * ``client.volume_connector.get`` for getting a volume connector - * ``client.volume_connector.update`` for updating a volume connector - * ``client.volume_connector.delete`` for deleting a volume connector - * ``client.node.list_volume_connectors`` for getting volume connectors - associated with a node diff --git a/releasenotes/notes/add-volume-connector-cli-873090474d5e41b9.yaml b/releasenotes/notes/add-volume-connector-cli-873090474d5e41b9.yaml deleted file mode 100644 index 7a8904e..0000000 --- a/releasenotes/notes/add-volume-connector-cli-873090474d5e41b9.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -features: - - | - Adds these ``openstack baremetal`` and ``ironic`` CLI commands - for volume connector resources. - - * ``openstack baremetal volume connector create`` - * ``openstack baremetal volume connector list`` - * ``openstack baremetal volume connector show`` - * ``openstack baremetal volume connector set`` - * ``openstack baremetal volume connector unset`` - * ``openstack baremetal volume connector delete`` - * ``ironic volume-connector-create`` - * ``ironic volume-connector-list`` - * ``ironic volume-connector-show`` - * ``ironic volume-connector-update`` - * ``ironic volume-connector-delete`` - - They are available starting with ironic API microversion 1.32. - diff --git a/releasenotes/notes/add-volume-target-api-e062303f4b3b40ef.yaml b/releasenotes/notes/add-volume-target-api-e062303f4b3b40ef.yaml deleted file mode 100644 index a597c01..0000000 --- a/releasenotes/notes/add-volume-target-api-e062303f4b3b40ef.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -features: - - | - Adds these python API client methods to support volume target resources - (available starting with API version 1.32): - - * ``client.volume_target.create`` for creating a volume target - * ``client.volume_target.list`` for listing volume targets - * ``client.volume_target.get`` for getting a volume target - * ``client.volume_target.update`` for updating a volume target - * ``client.volume_target.delete`` for deleting a volume target - * ``client.node.list_volume_targets`` for getting volume targets - associated with a node diff --git a/releasenotes/notes/add-volume-target-cli-e062303f4b3b40f0.yaml b/releasenotes/notes/add-volume-target-cli-e062303f4b3b40f0.yaml deleted file mode 100644 index b67a2b0..0000000 --- a/releasenotes/notes/add-volume-target-cli-e062303f4b3b40f0.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -features: - - | - Adds these ``openstack baremetal`` and ``ironic`` CLI commands for volume target resources. - - * ``openstack baremetal volume target create`` - * ``openstack baremetal volume target list`` - * ``openstack baremetal volume target show`` - * ``openstack baremetal volume target set`` - * ``openstack baremetal volume target unset`` - * ``openstack baremetal volume target delete`` - * ``ironic volume-target-create`` - * ``ironic volume-target-list`` - * ``ironic volume-target-show`` - * ``ironic volume-target-update`` - * ``ironic volume-target-delete`` - - They are available starting with ironic API microversion 1.32. diff --git a/releasenotes/notes/add_api_versions-a59e5b6899833c33.yaml b/releasenotes/notes/add_api_versions-a59e5b6899833c33.yaml deleted file mode 100644 index 88ba9a5..0000000 --- a/releasenotes/notes/add_api_versions-a59e5b6899833c33.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Add support to the openstackclient plugin for all Ironic API versions of - the form 1.x, up to the latest known minor version. The regular Ironic CLI - already supports all known versions. diff --git a/releasenotes/notes/bug-1524745-adds-node-create-args-a7ace744515e5943.yaml b/releasenotes/notes/bug-1524745-adds-node-create-args-a7ace744515e5943.yaml deleted file mode 100644 index 209705b..0000000 --- a/releasenotes/notes/bug-1524745-adds-node-create-args-a7ace744515e5943.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Add new arguments to the CLI node-create to allow selecting - boot, console, deploy, inspect, management, power, raid, and vendor - hardware interfaces, when hardware types are used. They are available - starting with ironic API microversion 1.31. diff --git a/releasenotes/notes/bug-1524745-extend-driver-list-and-driver-show-800d96393aa17342.yaml b/releasenotes/notes/bug-1524745-extend-driver-list-and-driver-show-800d96393aa17342.yaml deleted file mode 100644 index 3c3ab98..0000000 --- a/releasenotes/notes/bug-1524745-extend-driver-list-and-driver-show-800d96393aa17342.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -features: - - | - To support dynamic drivers (available starting with ironic API - microversion 1.30): - - * ironic driver-list has two new optional arguments, ``--type `` - for the type of driver ('classic' or 'dynamic') to list, and - ``--detail`` to show detailed information about the drivers. - * ironic driver-show returns a lot more information, including the type - of driver and the default and enabled interfaces. - * openstack baremetal driver list has two new optional arguments, - ``--type `` for the type of driver ('classic' or 'dynamic') - to list, and ``--long`` to show detailed information about the drivers. - * openstack baremetal driver show returns a lot more information, - including the type of driver and the default and enabled interfaces. \ No newline at end of file diff --git a/releasenotes/notes/bug-1524745-update-baremetal-node-set-c1ac57de0d481efe.yaml b/releasenotes/notes/bug-1524745-update-baremetal-node-set-c1ac57de0d481efe.yaml deleted file mode 100644 index 1cb14dd..0000000 --- a/releasenotes/notes/bug-1524745-update-baremetal-node-set-c1ac57de0d481efe.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Adds new arguments to the OSC baremetal-node-set to allow setting - boot, console, deploy, inspect, management, power, raid, and vendor - hardware interfaces. They are available starting with ironic API - microversion 1.30. \ No newline at end of file diff --git a/releasenotes/notes/continue-del-next-node-8827e67e1c41a0a5.yaml b/releasenotes/notes/continue-del-next-node-8827e67e1c41a0a5.yaml deleted file mode 100644 index 52f8acc..0000000 --- a/releasenotes/notes/continue-del-next-node-8827e67e1c41a0a5.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -fixes: - - when deleting multiple nodes, continue with deletes even if one fails. diff --git a/releasenotes/notes/display-empty-string-for-chassis-uuid-if-it-is-empty-a5471c3aa740a27d.yaml b/releasenotes/notes/display-empty-string-for-chassis-uuid-if-it-is-empty-a5471c3aa740a27d.yaml deleted file mode 100644 index b74481d..0000000 --- a/releasenotes/notes/display-empty-string-for-chassis-uuid-if-it-is-empty-a5471c3aa740a27d.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - | - If a node does not have ``chassis_uuid`` field in the API response, it - is added to the output of the node commands as an empty string. diff --git a/releasenotes/notes/driver-properties-for-osc-07a99d2d4e166436.yaml b/releasenotes/notes/driver-properties-for-osc-07a99d2d4e166436.yaml deleted file mode 100644 index 088c2e8..0000000 --- a/releasenotes/notes/driver-properties-for-osc-07a99d2d4e166436.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Adds the ``openstack baremetal driver property list `` command. - For the specified driver, this returns a list of its properties, along - with descriptions for each property. (The values of these properties - are specified in a node's driver_info.) diff --git a/releasenotes/notes/extend-vif-attach-commands-ef3a931413ddcee7.yaml b/releasenotes/notes/extend-vif-attach-commands-ef3a931413ddcee7.yaml deleted file mode 100644 index 01bc3ba..0000000 --- a/releasenotes/notes/extend-vif-attach-commands-ef3a931413ddcee7.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Adds ability to set custom VIF information fields via the `--vif-info ` - option in the `ironic node-vif-attach` and `openstack baremetal node vif attach` - commands. - diff --git a/releasenotes/notes/feature-parity-osc-cli-7606eed15f1c124f.yaml b/releasenotes/notes/feature-parity-osc-cli-7606eed15f1c124f.yaml deleted file mode 100644 index 060ee69..0000000 --- a/releasenotes/notes/feature-parity-osc-cli-7606eed15f1c124f.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -prelude: > - With this release, we have achieved feature parity between the - ``ironic`` and ``openstack baremetal`` (OpenStack Client plugin) CLI. diff --git a/releasenotes/notes/fix-python3-compatibility-993ace45fefcba34.yaml b/releasenotes/notes/fix-python3-compatibility-993ace45fefcba34.yaml deleted file mode 100644 index 12c7bd3..0000000 --- a/releasenotes/notes/fix-python3-compatibility-993ace45fefcba34.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - Fixes an issue in a python 3 environment, where TypeError - exceptions were being raised (due to the "requests" - library returning bytes instead of a string). diff --git a/releasenotes/notes/implicit-version-warning-d34b99727b50d519.yaml b/releasenotes/notes/implicit-version-warning-d34b99727b50d519.yaml deleted file mode 100644 index 3431415..0000000 --- a/releasenotes/notes/implicit-version-warning-d34b99727b50d519.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -deprecations: - - | - Currently, the default API version for the OSC plugin is fixed to be 1.9. - In the Queens release, it will be changed to the latest version understood - by both the client and the server. In this release a warning is logged, if - no explicit version is provided. diff --git a/releasenotes/notes/implicit-version-warning-old-cli-fe34d423ae63544a.yaml b/releasenotes/notes/implicit-version-warning-old-cli-fe34d423ae63544a.yaml deleted file mode 100644 index 29967f4..0000000 --- a/releasenotes/notes/implicit-version-warning-old-cli-fe34d423ae63544a.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -deprecations: - - | - Currently, the default API version for the ``ironic`` tool is fixed to be - 1.9. In the Queens release, it will be changed to the latest version - understood by both the client and the server. In this release a warning is - logged, if no explicit version is provided. diff --git a/releasenotes/notes/index-error-no-endpoint-eb281187f80a9aa4.yaml b/releasenotes/notes/index-error-no-endpoint-eb281187f80a9aa4.yaml deleted file mode 100644 index d12b2c4..0000000 --- a/releasenotes/notes/index-error-no-endpoint-eb281187f80a9aa4.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - Fail with EndpointException instead of IndexError while creating - v1 client without ``endpoint`` argument if os_ironic_api_version - isn't specified. diff --git a/releasenotes/notes/instance-crash-dump-d845a31e72b5a9f7.yaml b/releasenotes/notes/instance-crash-dump-d845a31e72b5a9f7.yaml deleted file mode 100644 index ae2edbc..0000000 --- a/releasenotes/notes/instance-crash-dump-d845a31e72b5a9f7.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Add a new command "ironic node-inject-nmi" to support the - injection of Non-Masking Interrupts (NMI). diff --git a/releasenotes/notes/ironic-create-files-fix-c31e40e566ff86b8.yaml b/releasenotes/notes/ironic-create-files-fix-c31e40e566ff86b8.yaml deleted file mode 100644 index 416febb..0000000 --- a/releasenotes/notes/ironic-create-files-fix-c31e40e566ff86b8.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -fixes: - - Fixes 'ironic create ' command so that it handles the - file argument(s) correctly. diff --git a/releasenotes/notes/keystone-token-auth-661a0c0d53c1b4de.yaml b/releasenotes/notes/keystone-token-auth-661a0c0d53c1b4de.yaml deleted file mode 100644 index 7268117..0000000 --- a/releasenotes/notes/keystone-token-auth-661a0c0d53c1b4de.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Added a possibility to pass os_auth_token instead of os_username and - os_password to authenticate in keystone both in CLI and in get_client - function. diff --git a/releasenotes/notes/latest-baremetal-api-version-a20e3099e3b97a1b.yaml b/releasenotes/notes/latest-baremetal-api-version-a20e3099e3b97a1b.yaml deleted file mode 100644 index edd3f7b..0000000 --- a/releasenotes/notes/latest-baremetal-api-version-a20e3099e3b97a1b.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - For OSC commands, the --os-baremetal-api-version optional argument - (or OS_BAREMETAL_API_VERSION environment variable) can have the - value 'latest'. If set to 'latest', the latest API version known by client - will be used in requests to the Bare Metal service. diff --git a/releasenotes/notes/list-nodes-by-driver-b1e1e1018077089b.yaml b/releasenotes/notes/list-nodes-by-driver-b1e1e1018077089b.yaml deleted file mode 100644 index 6768b8c..0000000 --- a/releasenotes/notes/list-nodes-by-driver-b1e1e1018077089b.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Add support for filtering nodes using the same driver in list command. diff --git a/releasenotes/notes/manual-clean-09f6b49df7d2513f.yaml b/releasenotes/notes/manual-clean-09f6b49df7d2513f.yaml deleted file mode 100644 index 1b65b20..0000000 --- a/releasenotes/notes/manual-clean-09f6b49df7d2513f.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - Adds support for manual cleaning API; available with ironic-api-version - 1.15 or higher. The ironic CLI is "ironic node-set-provision-state - --clean-steps " - where is 'clean' and is the clean steps - in JSON format. May be the path to a file containing the clean steps; - OR '-', with the clean steps being read from standard input; OR a string. - The value should be a list of clean-step dictionaries; each dictionary - should have keys 'interface' and 'step', and optional key 'args'. diff --git a/releasenotes/notes/negative-wrap-fix-4197e91b2ecfb722.yaml b/releasenotes/notes/negative-wrap-fix-4197e91b2ecfb722.yaml deleted file mode 100644 index b874c7f..0000000 --- a/releasenotes/notes/negative-wrap-fix-4197e91b2ecfb722.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -fixes: - - | - ``--wrap`` CLI argument for ``ironic driver-properties`` and - ``ironic driver-raid-logical-disk-properties`` commands now takes - only non-negative integers as input. An error is shown if a - negative value is passed. diff --git a/releasenotes/notes/no-resource-attributeerror-d0cb327abab7dcc0.yaml b/releasenotes/notes/no-resource-attributeerror-d0cb327abab7dcc0.yaml deleted file mode 100644 index 9e4e590..0000000 --- a/releasenotes/notes/no-resource-attributeerror-d0cb327abab7dcc0.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -fixes: - - For node resources that had no boot devices, no supported boot devices, or - no passthru methods (and driver resources with no properties or no passthru - methods), issuing a request to get that information (for example, - 'ironic driver-get-vendor-passthru-methods fake') would result in the - error "'NoneType' has no attribute 'to_dict'". This is fixed; an empty - list is now returned. diff --git a/releasenotes/notes/node-driver-support-storage-interface-e93fc8d4de5d24d6.yaml b/releasenotes/notes/node-driver-support-storage-interface-e93fc8d4de5d24d6.yaml deleted file mode 100644 index bd7e726..0000000 --- a/releasenotes/notes/node-driver-support-storage-interface-e93fc8d4de5d24d6.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -features: - - | - Adds support for storage_interface for the commands below. - They are available starting with ironic API microversion 1.33. - - * ``openstack baremetal node create`` - * ``openstack baremetal node show`` - * ``openstack baremetal node set`` - * ``openstack baremetal node unset`` - * ``openstack baremetal driver list`` - * ``openstack baremetal driver show`` - * ``ironic node-create`` - * ``ironic node-show`` - * ``ironic node-update`` - * ``ironic driver-list`` - * ``ironic driver-show`` diff --git a/releasenotes/notes/not-ignore-delete-failtures-0783d33a606ed6f1.yaml b/releasenotes/notes/not-ignore-delete-failtures-0783d33a606ed6f1.yaml deleted file mode 100644 index 5a4468f..0000000 --- a/releasenotes/notes/not-ignore-delete-failtures-0783d33a606ed6f1.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - Fixes an issue where deleting nodes ignore failures and just prints the results - which nodes are deleted and which are failed, always returning exit code of 0. - This now will return a non-zero exit code if at least one node-delete fails. diff --git a/releasenotes/notes/osc-baremetal-driver-raid-properties-159bd57058c0fc0e.yaml b/releasenotes/notes/osc-baremetal-driver-raid-properties-159bd57058c0fc0e.yaml deleted file mode 100644 index d14013d..0000000 --- a/releasenotes/notes/osc-baremetal-driver-raid-properties-159bd57058c0fc0e.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - Adds the ``openstack baremetal driver raid property list `` - command. For a specified driver, this returns a list of the - RAID logical disk properties that can be specified, along with - a description for each property. (The values of these properties - are specified in a node's ``target_raid_config`` field.) diff --git a/releasenotes/notes/osc-commands-1-7-d531960472a11ac2.yaml b/releasenotes/notes/osc-commands-1-7-d531960472a11ac2.yaml deleted file mode 100644 index 7932556..0000000 --- a/releasenotes/notes/osc-commands-1-7-d531960472a11ac2.yaml +++ /dev/null @@ -1,31 +0,0 @@ ---- -features: - - | - Adds new OpenStackClient commands: - - - * ``openstack baremetal chassis create`` - * ``openstack baremetal chassis delete`` - * ``openstack baremetal chassis list`` - * ``openstack baremetal chassis set`` - * ``openstack baremetal chassis show`` - * ``openstack baremetal chassis unset`` - * ``openstack baremetal driver list`` - * ``openstack baremetal driver passthru call`` - * ``openstack baremetal driver passthru list`` - * ``openstack baremetal driver show`` - * ``openstack baremetal node adopt`` - * ``openstack baremetal node boot device set`` - * ``openstack baremetal node boot device show`` - * ``openstack baremetal node console disable`` - * ``openstack baremetal node console enable`` - * ``openstack baremetal node console show`` - * ``openstack baremetal node passthru call`` - * ``openstack baremetal node passthru list`` - * ``openstack baremetal node validate`` - * ``openstack baremetal port delete`` - * ``openstack baremetal port list`` - * ``openstack baremetal port set`` - * ``openstack baremetal port unset`` - - Please see the help for each command for more information. diff --git a/releasenotes/notes/osc-default-microver-172d6e69316e70c1.yaml b/releasenotes/notes/osc-default-microver-172d6e69316e70c1.yaml deleted file mode 100644 index 33d7c55..0000000 --- a/releasenotes/notes/osc-default-microver-172d6e69316e70c1.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -fixes: - - Fixes the OpenStackClient plugin so that it uses the same - default API version as the Ironic CLI (1.9 instead of 1.6). diff --git a/releasenotes/notes/osc-instance-crash-dump-22634a57104561a5.yaml b/releasenotes/notes/osc-instance-crash-dump-22634a57104561a5.yaml deleted file mode 100644 index cda4344..0000000 --- a/releasenotes/notes/osc-instance-crash-dump-22634a57104561a5.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Add a new OSC command for the injection of Non-Masking Interrupts - (NMI), "openstack baremetal node inject nmi". diff --git a/releasenotes/notes/osc-max-microver-22-dc0d91a62f03a2e6.yaml b/releasenotes/notes/osc-max-microver-22-dc0d91a62f03a2e6.yaml deleted file mode 100644 index 0911b9e..0000000 --- a/releasenotes/notes/osc-max-microver-22-dc0d91a62f03a2e6.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -fixes: - - Fixes the OpenStackClient plugin so that - microversions 1.21 and 1.22 are supported. diff --git a/releasenotes/notes/osc-node-list-chassis-091d080684cdccf8.yaml b/releasenotes/notes/osc-node-list-chassis-091d080684cdccf8.yaml deleted file mode 100644 index 427ed4e..0000000 --- a/releasenotes/notes/osc-node-list-chassis-091d080684cdccf8.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Adds an option ``--chassis `` to the - ``openstack baremetal node list`` command. It provides the - ability to get a list of the nodes of the specified chassis. diff --git a/releasenotes/notes/osc-node-list-no-maintenance-ff1cef7cfbe60fb9.yaml b/releasenotes/notes/osc-node-list-no-maintenance-ff1cef7cfbe60fb9.yaml deleted file mode 100644 index 28dec48..0000000 --- a/releasenotes/notes/osc-node-list-no-maintenance-ff1cef7cfbe60fb9.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - For OSC, adds ability to get list of nodes that are not in - maintenance mode via the --no-maintenance optional argument - to the ``openstack baremetal node list`` command. diff --git a/releasenotes/notes/osc-node-list-option-driver-a2901ba6b4e1d3b5.yaml b/releasenotes/notes/osc-node-list-option-driver-a2901ba6b4e1d3b5.yaml deleted file mode 100644 index 417de11..0000000 --- a/releasenotes/notes/osc-node-list-option-driver-a2901ba6b4e1d3b5.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - For the OSC command ``openstack baremetal node list``, adds the - ``--driver `` option to limit the list to nodes with the - specified driver. diff --git a/releasenotes/notes/osc-node-list-provisionstate-cd98dbddaad93e96.yaml b/releasenotes/notes/osc-node-list-provisionstate-cd98dbddaad93e96.yaml deleted file mode 100644 index e56fa90..0000000 --- a/releasenotes/notes/osc-node-list-provisionstate-cd98dbddaad93e96.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -fixes: - - Allows all provision states for OSC node list - command with --provision-state argument diff --git a/releasenotes/notes/osc-node-list-unassociated-60e46958a0abc3e5.yaml b/releasenotes/notes/osc-node-list-unassociated-60e46958a0abc3e5.yaml deleted file mode 100644 index 91963a1..0000000 --- a/releasenotes/notes/osc-node-list-unassociated-60e46958a0abc3e5.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Adds an option ``--unassociated`` to the - ``openstack baremetal node list`` command. It provides the - ability to get a list of the nodes that are not associated - with instances. diff --git a/releasenotes/notes/osc-node-set-chassis-aae3413489b66b9b.yaml b/releasenotes/notes/osc-node-set-chassis-aae3413489b66b9b.yaml deleted file mode 100644 index 9d40242..0000000 --- a/releasenotes/notes/osc-node-set-chassis-aae3413489b66b9b.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - The chassis of a node can be set via the new --chassis-uuid - optional argument for ``openstack baremetal node set``. diff --git a/releasenotes/notes/osc-plugin-9b5344aceb886cc1.yaml b/releasenotes/notes/osc-plugin-9b5344aceb886cc1.yaml deleted file mode 100644 index c0b5cee..0000000 --- a/releasenotes/notes/osc-plugin-9b5344aceb886cc1.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Extend the OpenStackClient plugin with new commands: - - * openstack baremetal port show diff --git a/releasenotes/notes/osc-plugin-chassis-create-show-fix-ee276d707c5a5bdf.yaml b/releasenotes/notes/osc-plugin-chassis-create-show-fix-ee276d707c5a5bdf.yaml deleted file mode 100644 index bbe1ede..0000000 --- a/releasenotes/notes/osc-plugin-chassis-create-show-fix-ee276d707c5a5bdf.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - Hide nodes field in 'chasiss create' and 'chassis show' - OSC subcommand output because this field is not meant - for CLI users. diff --git a/releasenotes/notes/osc-plugin-f87e0fbb472261dd.yaml b/releasenotes/notes/osc-plugin-f87e0fbb472261dd.yaml deleted file mode 100644 index d199c08..0000000 --- a/releasenotes/notes/osc-plugin-f87e0fbb472261dd.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -features: - - | - Extend the OpenStackClient plugin with new commands: - - * openstack baremetal port group create - * openstack baremetal port group show - * openstack baremetal port group list - * openstack baremetal port group delete - * openstack baremetal port group set - * openstack baremetal port group unset - - Extends the 'openstack baremetal port' commands - (where applicable) to allow specifying the port group - (if any) that a port is a member of, via the new --port-group - argument. diff --git a/releasenotes/notes/osc-plugin-ff0d897d8441a9e1.yaml b/releasenotes/notes/osc-plugin-ff0d897d8441a9e1.yaml deleted file mode 100644 index 5c32994..0000000 --- a/releasenotes/notes/osc-plugin-ff0d897d8441a9e1.yaml +++ /dev/null @@ -1,36 +0,0 @@ ---- -features: - - | - Extend the OpenStackClient plugin with new commands: - - * openstack baremetal node abort - * openstack baremetal node clean - * openstack baremetal node create - * openstack baremetal node delete - Supports deleting multiple nodes - * openstack baremetal node deploy - * openstack baremetal node inspect - * openstack baremetal node list - * openstack baremetal node maintenance set - * opnestack baremetal node maintenance unset - * openstack baremetal node manage - * openstack baremetal node power - * openstack baremetal node provide - * openstack baremetal node reboot - * openstack baremetal node rebuild - * openstack baremetal node set - * openstack baremetal node show - * openstack baremetal node undeploy - * openstack baremetal node unset - * openstack baremetal port create -deprecations: - - | - Deprecating the following commands in favor of the new commands: - - * openstack baremetal create - * openstack baremetal delete - * openstack baremetal list - * openstack baremetal set - * openstack baremetal show - * openstack baremetal unset - - These will be removed in the 'Queens' release. diff --git a/releasenotes/notes/osc-plugin-node-create-show-fix-283148c86fbccce2.yaml b/releasenotes/notes/osc-plugin-node-create-show-fix-283148c86fbccce2.yaml deleted file mode 100644 index cfaba57..0000000 --- a/releasenotes/notes/osc-plugin-node-create-show-fix-283148c86fbccce2.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - Hide ports field in 'node create' and 'node show' - OSC subcommand output because this field is not meant - for CLI users. diff --git a/releasenotes/notes/osc-plugin-node-set-target-raid-config-5d538d6253902ecb.yaml b/releasenotes/notes/osc-plugin-node-set-target-raid-config-5d538d6253902ecb.yaml deleted file mode 100644 index 1e6787d..0000000 --- a/releasenotes/notes/osc-plugin-node-set-target-raid-config-5d538d6253902ecb.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Allows setting and unsetting (clearing) the node's target - RAID configuration via the OpenStackClient plugin commands - ``openstack baremetal node set --target-raid-config`` and - ``openstack baremetal node unset --target-raid-config`` - respectively. diff --git a/releasenotes/notes/osc-port-create-uuid-5da551b154540ef7.yaml b/releasenotes/notes/osc-port-create-uuid-5da551b154540ef7.yaml deleted file mode 100644 index 8ac6e75..0000000 --- a/releasenotes/notes/osc-port-create-uuid-5da551b154540ef7.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Adds the ``--uuid`` option for the ``openstack baremetal port create`` - command so that the new port's UUID can be specified. diff --git a/releasenotes/notes/osc-port-set-llc-pxeenabled-21fd8ea1982af17e.yaml b/releasenotes/notes/osc-port-set-llc-pxeenabled-21fd8ea1982af17e.yaml deleted file mode 100644 index 194ec63..0000000 --- a/releasenotes/notes/osc-port-set-llc-pxeenabled-21fd8ea1982af17e.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -features: - - | - For ``openstack baremetal port set``, adds these options: - - * ``--local-link-connection ``: Key/value metadata describing - local link connection information. Valid keys are ``switch_info``, - ``switch_id``, and ``port_id``. The keys ``switch_id`` and ``port_id`` - are required (repeat option to specify multiple keys). - * ``--pxe-enabled``: Indicates that this port should be used when PXE - booting this node (default) - * ``--pxe-disabled``: Indicates that this port should not be used when PXE - booting this node diff --git a/releasenotes/notes/osc-soft-reboot-poweroff-121b8043567f54a9.yaml b/releasenotes/notes/osc-soft-reboot-poweroff-121b8043567f54a9.yaml deleted file mode 100644 index ab38a15..0000000 --- a/releasenotes/notes/osc-soft-reboot-poweroff-121b8043567f54a9.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Enhances OSC to support soft reboot and soft power off with - power control timeout option. diff --git a/releasenotes/notes/osc-versioned-endpoint-fix-08f6b7af2f47a5d6.yaml b/releasenotes/notes/osc-versioned-endpoint-fix-08f6b7af2f47a5d6.yaml deleted file mode 100644 index 1b161be..0000000 --- a/releasenotes/notes/osc-versioned-endpoint-fix-08f6b7af2f47a5d6.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -fixes: - - Fixes an issue with OpenStackClient plugin not being able to work with - versioned ironic endpoints. diff --git a/releasenotes/notes/osc-wait-option-for-provisioning-commands-b6f5b875d573c9c8.yaml b/releasenotes/notes/osc-wait-option-for-provisioning-commands-b6f5b875d573c9c8.yaml deleted file mode 100644 index 570ee6b..0000000 --- a/releasenotes/notes/osc-wait-option-for-provisioning-commands-b6f5b875d573c9c8.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -features: - - | - Adds an option ``--wait []`` to all of the - OSC provisioning commands, except for abort which is not - supported. When specified, provisioning commands will - wait for the node to reach the desired state before - returning. An optional argument, time-out, can be specified - which will end the waiting after the specified amount of - time (in seconds). The default value for this timeout is - 0, which means it will wait indefinitely. diff --git a/releasenotes/notes/port-physical-network-6ea8860d773e473c.yaml b/releasenotes/notes/port-physical-network-6ea8860d773e473c.yaml deleted file mode 100644 index 420fcfd..0000000 --- a/releasenotes/notes/port-physical-network-6ea8860d773e473c.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Adds support for the ``port.physical_network`` field, which was introduced - in API version 1.34. diff --git a/releasenotes/notes/provision-state-adopt-d07b838813cecfb1.yaml b/releasenotes/notes/provision-state-adopt-d07b838813cecfb1.yaml deleted file mode 100644 index 9fb848b..0000000 --- a/releasenotes/notes/provision-state-adopt-d07b838813cecfb1.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Support has been added for the node-set-provision-state verb - ``adopt`` which requires API version 1.17. This feature allows - an operator move a node from ``MANAGABLE`` state to ``ACTIVE`` - state without performing cleaning or a deployment operation. diff --git a/releasenotes/notes/provision-state-wait-e7ff919ce8e13703.yaml b/releasenotes/notes/provision-state-wait-e7ff919ce8e13703.yaml deleted file mode 100644 index 148d156..0000000 --- a/releasenotes/notes/provision-state-wait-e7ff919ce8e13703.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Adds ``--wait`` flag to the ``ironic node-set-provision-state`` command and - the associated ``node.wait_for_provision_state`` method in the Python API. - The flag works with all provision state changes except for ``abort``. diff --git a/releasenotes/notes/raid_CLI_support-7e816ccd0fb31d2b.yaml b/releasenotes/notes/raid_CLI_support-7e816ccd0fb31d2b.yaml deleted file mode 100644 index 71219ba..0000000 --- a/releasenotes/notes/raid_CLI_support-7e816ccd0fb31d2b.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -features: - - | - Adds support for RAID configuration: - - * Ability to set target_raid_config for a node using - node-set-target-raid-config. - - * Displays target_raid_config and raid_config in - node-show. - - * Displays logical disk properties for a driver using - driver-raid-logical-disk-properties. - - API version 1.15 should be used with these features, as - RAID configuration was added in 1.12 and manual cleaning - (used to trigger RAID configuration) was added in 1.15. diff --git a/releasenotes/notes/remove-llc-short-arg-89c7443acc6c54a4.yaml b/releasenotes/notes/remove-llc-short-arg-89c7443acc6c54a4.yaml deleted file mode 100644 index e1f2635..0000000 --- a/releasenotes/notes/remove-llc-short-arg-89c7443acc6c54a4.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - Deprecates ``-l`` argument of ``openstack baremetal port create`` command - in favor of ``--local-link-connection``, as by OpenStackClient guidelines, - the options should be full words. diff --git a/releasenotes/notes/remove-states-field-0242960d121a09a7.yaml b/releasenotes/notes/remove-states-field-0242960d121a09a7.yaml deleted file mode 100644 index 5b376fc..0000000 --- a/releasenotes/notes/remove-states-field-0242960d121a09a7.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - Hides 'states' field in 'node create' and 'node show' - OSC subcommands output because this field is not meant - to be present in the output. diff --git a/releasenotes/notes/retry-on-keystone-auth-retriable-failures-91c08b9f8bdab7f3.yaml b/releasenotes/notes/retry-on-keystone-auth-retriable-failures-91c08b9f8bdab7f3.yaml deleted file mode 100644 index 963394c..0000000 --- a/releasenotes/notes/retry-on-keystone-auth-retriable-failures-91c08b9f8bdab7f3.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - The client will now retry on keystoneauth retriable connection failures if - retries are enabled for a particular request. This ensures that on a - temporary network outage to the keystone auth services a request we be - retried the requested number of times before raising an exception. diff --git a/releasenotes/notes/session-client-endpoint-override-20f1d822b4430afa.yaml b/releasenotes/notes/session-client-endpoint-override-20f1d822b4430afa.yaml deleted file mode 100644 index 1d11aed..0000000 --- a/releasenotes/notes/session-client-endpoint-override-20f1d822b4430afa.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - Fixes an issue when SessionClient ignores endpoint_override while doing - session requests, which leads to undeterministic results in multi-region - deployments. diff --git a/releasenotes/notes/show-required-arguments-in-help-commands-of-node-create-port-create-b213bb28bcc94743.yaml b/releasenotes/notes/show-required-arguments-in-help-commands-of-node-create-port-create-b213bb28bcc94743.yaml deleted file mode 100644 index 75aaade..0000000 --- a/releasenotes/notes/show-required-arguments-in-help-commands-of-node-create-port-create-b213bb28bcc94743.yaml +++ /dev/null @@ -1,6 +0,0 @@ -fixes: - - | - Where applicable, help for commands will output the required - arguments in a separate section from the optional arguments. - For example, the commands ``ironic help node-create`` and - ``ironic help port-create``. diff --git a/releasenotes/notes/soft-reboot-poweroff-e33d078a05db3894.yaml b/releasenotes/notes/soft-reboot-poweroff-e33d078a05db3894.yaml deleted file mode 100644 index cbbd530..0000000 --- a/releasenotes/notes/soft-reboot-poweroff-e33d078a05db3894.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Add optional arguments '--soft' and '--power-timeout' to the command - "node-set-power-state". diff --git a/releasenotes/notes/start-using-reno-ccd220efa2c7022a.yaml b/releasenotes/notes/start-using-reno-ccd220efa2c7022a.yaml deleted file mode 100644 index 873a30f..0000000 --- a/releasenotes/notes/start-using-reno-ccd220efa2c7022a.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -other: - - Start using reno to manage release notes. diff --git a/releasenotes/notes/switch-requests-8304d4465a8976b1.yaml b/releasenotes/notes/switch-requests-8304d4465a8976b1.yaml deleted file mode 100644 index 439e744..0000000 --- a/releasenotes/notes/switch-requests-8304d4465a8976b1.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Switch HTTP client to requests lib. It allows client to work with API - behind the proxy, configure proxies by setting the environment - variables HTTP_PROXY and HTTPS_PROXY. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 8f30b28..0000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,284 +0,0 @@ -# -*- coding: utf-8 -*- -# 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. -# -# Ironic Client Release Notes documentation build configuration file, created -# by sphinx-quickstart on Wed Dec 23 22:54:56 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# openstackdocstheme options -repository_name = 'openstack/python-ironicclient' -bug_project = 'python-ironicclient' -bug_tag = '' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Ironic Client Release Notes' -copyright = u'2015, Ironic Developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -import pbr.version -ironicclient_version = pbr.version.VersionInfo('python-ironicclient') -# The short X.Y version. -version = ironicclient_version.canonical_version_string() -# The full version, including alpha/beta/rc tags. -release = ironicclient_version.version_string_with_vcs() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'IronicClientReleaseNotesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'IronicClientReleaseNotes.tex', - u'Ironic Client Release Notes Documentation', - u'Ironic Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'ironicclientreleasenotes', - u'Ironic Client Release Notes Documentation', - [u'Ironic Developers'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'IronicClientReleaseNotes', - u'Ironic Client Release Notes Documentation', - u'Ironic Developers', 'IronicClientReleaseNotes', - 'Bare metal provisioning service client.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index e37bd5f..0000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -============================= - Ironic Client Release Notes -============================= - -.. toctree:: - :maxdepth: 1 - - unreleased - ocata - newton - mitaka diff --git a/releasenotes/source/mitaka.rst b/releasenotes/source/mitaka.rst deleted file mode 100644 index e545609..0000000 --- a/releasenotes/source/mitaka.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Mitaka Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/mitaka diff --git a/releasenotes/source/newton.rst b/releasenotes/source/newton.rst deleted file mode 100644 index 97036ed..0000000 --- a/releasenotes/source/newton.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Newton Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/newton diff --git a/releasenotes/source/ocata.rst b/releasenotes/source/ocata.rst deleted file mode 100644 index ebe62f4..0000000 --- a/releasenotes/source/ocata.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Ocata Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/ocata diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index cd22aab..0000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================== - Current Series Release Notes -============================== - -.. release-notes:: diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 46e7c90..0000000 --- a/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -pbr!=2.1.0,>=2.0.0 # Apache-2.0 -appdirs>=1.3.0 # MIT License -dogpile.cache>=0.6.2 # BSD -jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT -keystoneauth1>=3.0.1 # Apache-2.0 -osc-lib>=1.7.0 # Apache-2.0 -oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0 -oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0 -oslo.utils>=3.20.0 # Apache-2.0 -PrettyTable<0.8,>=0.7.1 # BSD -python-openstackclient!=3.10.0,>=3.3.0 # Apache-2.0 -PyYAML>=3.10.0 # MIT -requests>=2.14.2 # Apache-2.0 -six>=1.9.0 # MIT diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 02c4f88..0000000 --- a/setup.cfg +++ /dev/null @@ -1,117 +0,0 @@ -[metadata] -name = python-ironicclient -summary = OpenStack Bare Metal Provisioning API Client Library -description-file = README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = https://docs.openstack.org/python-ironicclient/latest/ -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 - -[files] -packages = ironicclient - -[entry_points] -console_scripts = - ironic = ironicclient.shell:main - -openstack.cli.extension = - baremetal = ironicclient.osc.plugin - -openstack.baremetal.v1 = - baremetal_chassis_create = ironicclient.osc.v1.baremetal_chassis:CreateBaremetalChassis - baremetal_chassis_delete = ironicclient.osc.v1.baremetal_chassis:DeleteBaremetalChassis - baremetal_chassis_list = ironicclient.osc.v1.baremetal_chassis:ListBaremetalChassis - baremetal_chassis_set = ironicclient.osc.v1.baremetal_chassis:SetBaremetalChassis - baremetal_chassis_show = ironicclient.osc.v1.baremetal_chassis:ShowBaremetalChassis - baremetal_chassis_unset = ironicclient.osc.v1.baremetal_chassis:UnsetBaremetalChassis - baremetal_create = ironicclient.osc.v1.baremetal_create:CreateBaremetal - baremetal_delete = ironicclient.osc.v1.baremetal_node:DeleteBaremetal - baremetal_driver_list = ironicclient.osc.v1.baremetal_driver:ListBaremetalDriver - baremetal_driver_passthru_call = ironicclient.osc.v1.baremetal_driver:PassthruCallBaremetalDriver - baremetal_driver_passthru_list = ironicclient.osc.v1.baremetal_driver:PassthruListBaremetalDriver - baremetal_driver_property_list = ironicclient.osc.v1.baremetal_driver:ListBaremetalDriverProperty - baremetal_driver_raid_property_list = ironicclient.osc.v1.baremetal_driver:ListBaremetalDriverRaidProperty - baremetal_driver_show = ironicclient.osc.v1.baremetal_driver:ShowBaremetalDriver - baremetal_list = ironicclient.osc.v1.baremetal_node:ListBaremetal - baremetal_node_abort = ironicclient.osc.v1.baremetal_node:AbortBaremetalNode - baremetal_node_adopt = ironicclient.osc.v1.baremetal_node:AdoptBaremetalNode - baremetal_node_boot_device_set = ironicclient.osc.v1.baremetal_node:BootdeviceSetBaremetalNode - baremetal_node_boot_device_show = ironicclient.osc.v1.baremetal_node:BootdeviceShowBaremetalNode - baremetal_node_clean = ironicclient.osc.v1.baremetal_node:CleanBaremetalNode - baremetal_node_console_disable = ironicclient.osc.v1.baremetal_node:ConsoleDisableBaremetalNode - baremetal_node_console_enable = ironicclient.osc.v1.baremetal_node:ConsoleEnableBaremetalNode - baremetal_node_console_show = ironicclient.osc.v1.baremetal_node:ConsoleShowBaremetalNode - baremetal_node_create = ironicclient.osc.v1.baremetal_node:CreateBaremetalNode - baremetal_node_delete = ironicclient.osc.v1.baremetal_node:DeleteBaremetalNode - baremetal_node_deploy = ironicclient.osc.v1.baremetal_node:DeployBaremetalNode - baremetal_node_inspect = ironicclient.osc.v1.baremetal_node:InspectBaremetalNode - baremetal_node_list = ironicclient.osc.v1.baremetal_node:ListBaremetalNode - baremetal_node_maintenance_set = ironicclient.osc.v1.baremetal_node:MaintenanceSetBaremetalNode - baremetal_node_maintenance_unset = ironicclient.osc.v1.baremetal_node:MaintenanceUnsetBaremetalNode - baremetal_node_manage = ironicclient.osc.v1.baremetal_node:ManageBaremetalNode - baremetal_node_passthru_call = ironicclient.osc.v1.baremetal_node:PassthruCallBaremetalNode - baremetal_node_passthru_list = ironicclient.osc.v1.baremetal_node:PassthruListBaremetalNode - baremetal_node_power = ironicclient.osc.v1.baremetal_node:PowerBaremetalNode - baremetal_node_provide = ironicclient.osc.v1.baremetal_node:ProvideBaremetalNode - baremetal_node_reboot = ironicclient.osc.v1.baremetal_node:RebootBaremetalNode - baremetal_node_rebuild = ironicclient.osc.v1.baremetal_node:RebuildBaremetalNode - baremetal_node_set = ironicclient.osc.v1.baremetal_node:SetBaremetalNode - baremetal_node_show = ironicclient.osc.v1.baremetal_node:ShowBaremetalNode - baremetal_node_undeploy = ironicclient.osc.v1.baremetal_node:UndeployBaremetalNode - baremetal_node_unset = ironicclient.osc.v1.baremetal_node:UnsetBaremetalNode - baremetal_node_validate = ironicclient.osc.v1.baremetal_node:ValidateBaremetalNode - baremetal_node_vif_attach = ironicclient.osc.v1.baremetal_node:VifAttachBaremetalNode - baremetal_node_vif_detach = ironicclient.osc.v1.baremetal_node:VifDetachBaremetalNode - baremetal_node_vif_list = ironicclient.osc.v1.baremetal_node:VifListBaremetalNode - baremetal_node_inject_nmi = ironicclient.osc.v1.baremetal_node:InjectNmiBaremetalNode - baremetal_port_create = ironicclient.osc.v1.baremetal_port:CreateBaremetalPort - baremetal_port_delete = ironicclient.osc.v1.baremetal_port:DeleteBaremetalPort - baremetal_port_list = ironicclient.osc.v1.baremetal_port:ListBaremetalPort - baremetal_port_set = ironicclient.osc.v1.baremetal_port:SetBaremetalPort - baremetal_port_show = ironicclient.osc.v1.baremetal_port:ShowBaremetalPort - baremetal_port_unset = ironicclient.osc.v1.baremetal_port:UnsetBaremetalPort - baremetal_port_group_create = ironicclient.osc.v1.baremetal_portgroup:CreateBaremetalPortGroup - baremetal_port_group_delete = ironicclient.osc.v1.baremetal_portgroup:DeleteBaremetalPortGroup - baremetal_port_group_list = ironicclient.osc.v1.baremetal_portgroup:ListBaremetalPortGroup - baremetal_port_group_set = ironicclient.osc.v1.baremetal_portgroup:SetBaremetalPortGroup - baremetal_port_group_show = ironicclient.osc.v1.baremetal_portgroup:ShowBaremetalPortGroup - baremetal_port_group_unset = ironicclient.osc.v1.baremetal_portgroup:UnsetBaremetalPortGroup - baremetal_volume_connector_create = ironicclient.osc.v1.baremetal_volume_connector:CreateBaremetalVolumeConnector - baremetal_volume_connector_delete = ironicclient.osc.v1.baremetal_volume_connector:DeleteBaremetalVolumeConnector - baremetal_volume_connector_list = ironicclient.osc.v1.baremetal_volume_connector:ListBaremetalVolumeConnector - baremetal_volume_connector_set = ironicclient.osc.v1.baremetal_volume_connector:SetBaremetalVolumeConnector - baremetal_volume_connector_show = ironicclient.osc.v1.baremetal_volume_connector:ShowBaremetalVolumeConnector - baremetal_volume_connector_unset = ironicclient.osc.v1.baremetal_volume_connector:UnsetBaremetalVolumeConnector - baremetal_volume_target_create = ironicclient.osc.v1.baremetal_volume_target:CreateBaremetalVolumeTarget - baremetal_volume_target_delete = ironicclient.osc.v1.baremetal_volume_target:DeleteBaremetalVolumeTarget - baremetal_volume_target_list = ironicclient.osc.v1.baremetal_volume_target:ListBaremetalVolumeTarget - baremetal_volume_target_set = ironicclient.osc.v1.baremetal_volume_target:SetBaremetalVolumeTarget - baremetal_volume_target_show = ironicclient.osc.v1.baremetal_volume_target:ShowBaremetalVolumeTarget - baremetal_volume_target_unset = ironicclient.osc.v1.baremetal_volume_target:UnsetBaremetalVolumeTarget - baremetal_set = ironicclient.osc.v1.baremetal_node:SetBaremetal - baremetal_show = ironicclient.osc.v1.baremetal_node:ShowBaremetal - baremetal_unset = ironicclient.osc.v1.baremetal_node:UnsetBaremetal - -[pbr] -autodoc_index_modules = True -autodoc_exclude_modules = - ironicclient.tests.functional.* -warnerrors = True - -[build_sphinx] -all_files = 1 -build-dir = doc/build -source-dir = doc/source - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 566d844..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 22f529d..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,19 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 -coverage!=4.4,>=4.0 # Apache-2.0 -doc8 # Apache-2.0 -fixtures>=3.0.0 # Apache-2.0/BSD -requests-mock>=1.1 # Apache-2.0 -mock>=2.0 # BSD -Babel!=2.4.0,>=2.3.4 # BSD -openstackdocstheme>=1.11.0 # Apache-2.0 -reno!=2.3.1,>=1.8.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 -python-subunit>=0.0.18 # Apache-2.0/BSD -sphinx>=1.6.2 # BSD -testtools>=1.4.0 # MIT -tempest>=16.1.0 # Apache-2.0 -os-testr>=0.8.0 # Apache-2.0 -ddt>=1.0.1 # MIT diff --git a/tools/__init__.py b/tools/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py deleted file mode 100644 index b0bada1..0000000 --- a/tools/install_venv_common.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# Copyright 2013 IBM Corp. -# -# 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. - -"""Provides methods needed by installation script for OpenStack development -virtual environments. - -Since this script is used to bootstrap a virtualenv from the system's Python -environment, it should be kept strictly compatible with Python 2.7. - -Synced in from openstack-common -""" - -from __future__ import print_function - -import optparse -import os -import subprocess -import sys - - -class InstallVenv(object): - - def __init__(self, root, venv, requirements, - test_requirements, py_version, - project): - self.root = root - self.venv = venv - self.requirements = requirements - self.test_requirements = test_requirements - self.py_version = py_version - self.project = project - - def die(self, message, *args): - print(message % args, file=sys.stderr) - sys.exit(1) - - def check_python_version(self): - if sys.version_info < (2, 7): - self.die("Need Python Version >= 2.7") - - def run_command_with_code(self, cmd, redirect_output=True, - check_exit_code=True): - """Runs a command in an out-of-process shell. - - Returns the output of that command. Working directory is self.root. - """ - if redirect_output: - stdout = subprocess.PIPE - else: - stdout = None - - proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout) - output = proc.communicate()[0] - if check_exit_code and proc.returncode != 0: - self.die('Command "%s" failed.\n%s', ' '.join(cmd), output) - return (output, proc.returncode) - - def run_command(self, cmd, redirect_output=True, check_exit_code=True): - return self.run_command_with_code(cmd, redirect_output, - check_exit_code)[0] - - def get_distro(self): - if (os.path.exists('/etc/fedora-release') or - os.path.exists('/etc/redhat-release')): - return Fedora( - self.root, self.venv, self.requirements, - self.test_requirements, self.py_version, self.project) - else: - return Distro( - self.root, self.venv, self.requirements, - self.test_requirements, self.py_version, self.project) - - def check_dependencies(self): - self.get_distro().install_virtualenv() - - def create_virtualenv(self, no_site_packages=True): - """Creates the virtual environment and installs PIP. - - Creates the virtual environment and installs PIP only into the - virtual environment. - """ - if not os.path.isdir(self.venv): - print('Creating venv...', end=' ') - if no_site_packages: - self.run_command(['virtualenv', '-q', '--no-site-packages', - self.venv]) - else: - self.run_command(['virtualenv', '-q', self.venv]) - print('done.') - else: - print("venv already exists...") - pass - - def pip_install(self, *args): - self.run_command(['tools/with_venv.sh', - 'pip', 'install', '--upgrade'] + list(args), - redirect_output=False) - - def install_dependencies(self): - print('Installing dependencies with pip (this can take a while)...') - - # First things first, make sure our venv has the latest pip and - # setuptools. - self.pip_install('pip>=1.3') - self.pip_install('setuptools') - - self.pip_install('-r', self.requirements) - self.pip_install('-r', self.test_requirements) - - def post_process(self): - self.get_distro().post_process() - - def parse_args(self, argv): - """Parses command-line arguments.""" - parser = optparse.OptionParser() - parser.add_option('-n', '--no-site-packages', - action='store_true', - help="Do not inherit packages from global Python " - "install") - return parser.parse_args(argv[1:])[0] - - -class Distro(InstallVenv): - - def check_cmd(self, cmd): - return bool(self.run_command(['which', cmd], - check_exit_code=False).strip()) - - def install_virtualenv(self): - if self.check_cmd('virtualenv'): - return - - if self.check_cmd('easy_install'): - print('Installing virtualenv via easy_install...', end=' ') - if self.run_command(['easy_install', 'virtualenv']): - print('Succeeded') - return - else: - print('Failed') - - self.die('ERROR: virtualenv not found.\n\n%s development' - ' requires virtualenv, please install it using your' - ' favorite package management tool' % self.project) - - def post_process(self): - """Any distribution-specific post-processing gets done here. - - In particular, this is useful for applying patches to code inside - the venv. - """ - pass - - -class Fedora(Distro): - """This covers all Fedora-based distributions. - - Includes: Fedora, RHEL, CentOS, Scientific Linux - """ - - def check_pkg(self, pkg): - return self.run_command_with_code(['rpm', '-q', pkg], - check_exit_code=False)[1] == 0 - - def apply_patch(self, originalfile, patchfile): - self.run_command(['patch', '-N', originalfile, patchfile], - check_exit_code=False) - - def install_virtualenv(self): - if self.check_cmd('virtualenv'): - return - - if not self.check_pkg('python-virtualenv'): - self.die("Please install 'python-virtualenv'.") - - super(Fedora, self).install_virtualenv() - - def post_process(self): - """Workaround for a bug in eventlet. - - This currently affects RHEL6.1, but the fix can safely be - applied to all RHEL and Fedora distributions. - - This can be removed when the fix is applied upstream. - - Nova: https://bugs.launchpad.net/nova/+bug/884915 - Upstream: https://bitbucket.org/eventlet/eventlet/issue/89 - RHEL: https://bugzilla.redhat.com/958868 - """ - - # Install "patch" program if it's not there - if not self.check_pkg('patch'): - self.die("Please install 'patch'.") - - # Apply the eventlet patch - self.apply_patch(os.path.join(self.venv, 'lib', self.py_version, - 'site-packages', - 'eventlet/green/subprocess.py'), - 'contrib/redhat-eventlet.patch') diff --git a/tools/ironic.bash_completion b/tools/ironic.bash_completion deleted file mode 100644 index fbc32f2..0000000 --- a/tools/ironic.bash_completion +++ /dev/null @@ -1,27 +0,0 @@ -_ironic_opts="" # lazy init -_ironic_flags="" # lazy init -_ironic_opts_exp="" # lazy init -_ironic() -{ - local cur prev nbc cflags - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - - if [ "x$_ironic_opts" == "x" ] ; then - nbc="`ironic bash-completion | sed -e "s/ *-h */ /" -e "s/ *-i */ /"`" - _ironic_opts="`echo "$nbc" | sed -e "s/--[a-z0-9_-]*//g" -e "s/ */ /g"`" - _ironic_flags="`echo " $nbc" | sed -e "s/ [^-][^-][a-z0-9_-]*//g" -e "s/ */ /g"`" - _ironic_opts_exp="`echo "$_ironic_opts" | tr ' ' '|'`" - fi - - if [[ " ${COMP_WORDS[@]} " =~ " "($_ironic_opts_exp)" " && "$prev" != "help" ]] ; then - COMPLETION_CACHE=$HOME/.cache/python-ironicclient/*/*-cache - cflags="$_ironic_flags "$(cat $COMPLETION_CACHE 2> /dev/null | tr '\n' ' ') - COMPREPLY=($(compgen -W "${cflags}" -- ${cur})) - else - COMPREPLY=($(compgen -W "${_ironic_opts}" -- ${cur})) - fi - return 0 -} -complete -F _ironic ironic diff --git a/tools/run_functional.sh b/tools/run_functional.sh deleted file mode 100755 index e972519..0000000 --- a/tools/run_functional.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -FUNC_TEST_DIR=$(dirname $0)/../ironicclient/tests/functional/ -CONFIG_FILE=$FUNC_TEST_DIR/test.conf - -if [[ -n "$OS_AUTH_TOKEN" ]] && [[ -n "$IRONIC_URL" ]]; then -cat <$CONFIG_FILE -[functional] -api_version = 1 -auth_strategy=noauth -os_auth_token=$OS_AUTH_TOKEN -ironic_url=$IRONIC_URL -END -else -cat <$CONFIG_FILE -[functional] -api_version = 1 -os_auth_url=$OS_AUTH_URL -os_identity_api_version = $OS_IDENTITY_API_VERSION -os_username=$OS_USERNAME -os_password=$OS_PASSWORD -os_project_name=$OS_PROJECT_NAME -os_user_domain_id=$OS_USER_DOMAIN_ID -os_project_domain_id=$OS_PROJECT_DOMAIN_ID -os_service_type=baremetal -os_endpoint_type=public -END -fi -tox -e functional diff --git a/tools/tox_install.sh b/tools/tox_install.sh deleted file mode 100755 index d74243f..0000000 --- a/tools/tox_install.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash - -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should replace the version pin in -# the constraints file before applying it for from-source installation. - -ZUUL_CLONER=/usr/zuul-env/bin/zuul-cloner -BRANCH_NAME=master -CLIENT_NAME=python-ironicclient -requirements_installed=$(echo "import openstack_requirements" | python 2>/dev/null ; echo $?) - -set -e - -CONSTRAINTS_FILE=$1 -shift - -install_cmd="pip install" -mydir=$(mktemp -dt "$CLIENT_NAME-tox_install-XXXXXXX") -trap "rm -rf $mydir" EXIT -localfile=$mydir/upper-constraints.txt -if [[ $CONSTRAINTS_FILE != http* ]]; then - CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE -fi -curl $CONSTRAINTS_FILE -k -o $localfile -install_cmd="$install_cmd -c$localfile" - -if [ $requirements_installed -eq 0 ]; then - echo "ALREADY INSTALLED" > /tmp/tox_install.txt - echo "Requirements already installed; using existing package" -elif [ -x "$ZUUL_CLONER" ]; then - echo "ZUUL CLONER" > /tmp/tox_install.txt - pushd $mydir - $ZUUL_CLONER --cache-dir \ - /opt/git \ - --branch $BRANCH_NAME \ - git://git.openstack.org \ - openstack/requirements - cd openstack/requirements - $install_cmd -e . - popd -else - echo "PIP HARDCODE" > /tmp/tox_install.txt - if [ -z "$REQUIREMENTS_PIP_LOCATION" ]; then - REQUIREMENTS_PIP_LOCATION="git+https://git.openstack.org/openstack/requirements@$BRANCH_NAME#egg=requirements" - fi - $install_cmd -U -e ${REQUIREMENTS_PIP_LOCATION} -fi - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints $localfile -- $CLIENT_NAME "-e file://$PWD#egg=$CLIENT_NAME" - -$install_cmd -U $* -exit $? diff --git a/tools/with_venv.sh b/tools/with_venv.sh deleted file mode 100755 index 94e05c1..0000000 --- a/tools/with_venv.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -tools_path=${tools_path:-$(dirname $0)} -venv_path=${venv_path:-${tools_path}} -venv_dir=${venv_name:-/../.venv} -TOOLS=${tools_path} -VENV=${venv:-${venv_path}/${venv_dir}} -source ${VENV}/bin/activate && "$@" diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 59fc63a..0000000 --- a/tox.ini +++ /dev/null @@ -1,59 +0,0 @@ -[tox] -minversion = 1.6 -envlist = py35,py27,pep8,pypy -skipsdist = True - -[testenv] -setenv = VIRTUAL_ENV={envdir} - PYTHONDONTWRITEBYTECODE = 1 - LANGUAGE=en_US - # .testr.conf uses TESTS_DIR - TESTS_DIR=./ironicclient/tests/unit -usedevelop = True -install_command = - {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} -deps = - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = - ostestr {posargs} - -[testenv:releasenotes] -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html - -[testenv:pep8] -commands = - flake8 {posargs} - doc8 doc/source CONTRIBUTING.rst README.rst - -[testenv:cover] -setenv = VIRTUAL_ENV={envdir} - LANGUAGE=en_US -commands = - coverage erase - python setup.py testr --coverage --testr-args='{posargs}' - -[testenv:venv] -commands = {posargs} - -[testenv:functional] -setenv = TESTS_DIR=./ironicclient/tests/functional - LANGUAGE=en_US - -[testenv:docs] -setenv = PYTHONHASHSEED=0 -sitepackages = False -envdir = {toxworkdir}/venv -commands = - python setup.py build_sphinx - -[flake8] -ignore = -exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools -# [H106] Don't put vim configuration in source files. -# [H203] Use assertIs(Not)None to check for None. -# [H904] Delay string interpolations at logging calls. -enable-extensions=H106,H203,H904 - -[hacking] -import_exceptions = testtools.matchers, ironicclient.common.i18n