├── .coveragerc ├── .gitignore ├── .gitreview ├── .pylintrc ├── .stestr.conf ├── .zuul.yaml ├── CONTRIBUTING.rst ├── HACKING.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── doc ├── requirements.txt └── source │ ├── cli │ ├── commands.rst │ ├── index.rst │ ├── vim_commands.rst │ ├── vnf_package_commands.rst │ ├── vnffm_commands.rst │ ├── vnflcm_commands.rst │ └── vnfpm_commands.rst │ ├── conf.py │ ├── contributor │ ├── contributing.rst │ ├── developing.rst │ └── index.rst │ ├── index.rst │ ├── install │ └── index.rst │ └── reference │ └── index.rst ├── releasenotes ├── notes │ ├── add-creating-ns-vnffg-from-template-213eee7f1820aa0c.yaml │ ├── add-vnffg-and-vnf-ids-to-ns-list-commands-9d462efc103f8ecb.yaml │ ├── bug-1750865-04c3ebd0c3f8af29.yaml │ ├── bug-1754556-53268d3081fa18d1.yaml │ ├── bug-1754793-54446bcd0a4e84aa.yaml │ ├── bug-1754926-06ac4d7ffd17b5ce.yaml │ ├── clustering-service-cli-e15cc6627de293fa.yaml │ ├── del-project_and_user_id-e9dd396f83a162d6.yaml │ ├── deprecate-direct-yaml-cli-input-812564bab1b99b4b.yaml │ ├── deprecate-infra-mgmt-driver-attributes-e371624c50accee8.yaml │ ├── deprecate-legacy-apis-excluding-vim-debaa69507f73179.yaml │ ├── deprecated-tacker-command-29121558bd748082.yaml │ ├── drop-py-2-7-b2052825c4b92b52.yaml │ ├── multi-delete-support-in-tacker-acd4a7e86114f0be.yaml │ ├── network-services-descriptor-06f6abe90adb40f3.yaml │ ├── new-commmand-vnf-resource-list-d5422ab917f0892f.yaml │ ├── obsolete-legacy-apis-excluding-vim-43d8dd73c3768fbb.yaml │ ├── remove-passing-mgmt-and-infra-driver-from-client-c9135f84480b2cae.yaml │ ├── tacker-support-python-openstackclient-b88b20b80b872229.yaml │ ├── update-vim-without-config-c3b637741889eff6.yaml │ ├── vnf-inline-template-25f6a0b66f7407a1.yaml │ ├── vnfd-vnf-vim-name-mandatory-in-tacker-cli-dfe802af6de5c80e.yaml │ └── vnffg-client-abd7d7f06860b91d.yaml └── source │ ├── 2023.1.rst │ ├── 2023.2.rst │ ├── 2024.1.rst │ ├── 2024.2.rst │ ├── 2025.1.rst │ ├── _static │ └── .placeholder │ ├── _templates │ └── .placeholder │ ├── conf.py │ ├── index.rst │ ├── newton.rst │ ├── ocata.rst │ ├── pike.rst │ ├── queens.rst │ ├── rocky.rst │ ├── stein.rst │ ├── train.rst │ ├── unreleased.rst │ ├── ussuri.rst │ ├── victoria.rst │ ├── wallaby.rst │ ├── xena.rst │ ├── yoga.rst │ └── zed.rst ├── requirements.txt ├── setup.cfg ├── setup.py ├── tackerclient ├── __init__.py ├── client.py ├── common │ ├── __init__.py │ ├── _i18n.py │ ├── clientmanager.py │ ├── command.py │ ├── constants.py │ ├── exceptions.py │ ├── extension.py │ ├── serializer.py │ ├── utils.py │ └── validators.py ├── i18n.py ├── osc │ ├── __init__.py │ ├── common │ │ ├── __init__.py │ │ └── vnflcm │ │ │ ├── __init__.py │ │ │ └── vnflcm_versions.py │ ├── plugin.py │ ├── sdk_utils.py │ ├── utils.py │ ├── v1 │ │ ├── __init__.py │ │ ├── nfvo │ │ │ ├── __init__.py │ │ │ └── vim.py │ │ ├── vnflcm │ │ │ ├── __init__.py │ │ │ ├── samples │ │ │ │ ├── change_ext_conn_vnf_instance_param_sample.json │ │ │ │ ├── create_lccn_subscription_param_sample.json │ │ │ │ ├── heal_vnf_instance_param_sample.json │ │ │ │ ├── instantiate_vnf_instance_param_sample.json │ │ │ │ ├── scale_vnf_instance_param_sample.json │ │ │ │ └── update_vnf_instance_param_sample.json │ │ │ ├── vnflcm.py │ │ │ ├── vnflcm_op_occs.py │ │ │ └── vnflcm_subsc.py │ │ └── vnfpkgm │ │ │ ├── __init__.py │ │ │ └── vnf_package.py │ └── v2 │ │ ├── __init__.py │ │ ├── vnffm │ │ ├── __init__.py │ │ ├── samples │ │ │ └── create_vnf_fm_subscription_param_sample.json │ │ ├── vnffm_alarm.py │ │ └── vnffm_sub.py │ │ ├── vnflcm │ │ └── samples │ │ │ └── change_vnfpkg_vnf_instance_param_sample.json │ │ └── vnfpm │ │ ├── __init__.py │ │ ├── samples │ │ ├── create_vnf_pm_job_param_sample.json │ │ ├── create_vnf_pm_threshold_param_sample.json │ │ ├── update_vnf_pm_job_param_sample.json │ │ └── update_vnf_pm_threshold_param_sample.json │ │ ├── vnfpm_job.py │ │ ├── vnfpm_report.py │ │ └── vnfpm_threshold.py ├── shell.py ├── tacker │ ├── __init__.py │ ├── client.py │ └── v1_0 │ │ ├── __init__.py │ │ └── nfvo │ │ ├── __init__.py │ │ ├── vim.py │ │ └── vim_utils.py ├── tests │ ├── __init__.py │ └── unit │ │ ├── __init__.py │ │ ├── osc │ │ ├── __init__.py │ │ ├── base.py │ │ ├── common │ │ │ ├── __init__.py │ │ │ └── test_vnflcm_versions.py │ │ ├── v1 │ │ │ ├── __init__.py │ │ │ ├── fixture_data │ │ │ │ ├── __init__.py │ │ │ │ ├── client.py │ │ │ │ ├── sample_vnf_package │ │ │ │ │ ├── Definitions │ │ │ │ │ │ ├── etsi_nfv_sol001_common_types.yaml │ │ │ │ │ │ ├── etsi_nfv_sol001_vnfd_types.yaml │ │ │ │ │ │ ├── helloworld3_df_simple.yaml │ │ │ │ │ │ ├── helloworld3_top.vnfd.yaml │ │ │ │ │ │ └── helloworld3_types.yaml │ │ │ │ │ └── TOSCA-Metadata │ │ │ │ │ │ └── TOSCA.meta │ │ │ │ └── sample_vnf_package_artifacts │ │ │ │ │ ├── Definitions │ │ │ │ │ ├── etsi_nfv_sol001_common_types.yaml │ │ │ │ │ ├── etsi_nfv_sol001_vnfd_types.yaml │ │ │ │ │ ├── helloworld3_df_simple.yaml │ │ │ │ │ ├── helloworld3_top.vnfd.yaml │ │ │ │ │ └── helloworld3_types.yaml │ │ │ │ │ ├── Scripts │ │ │ │ │ └── install.sh │ │ │ │ │ └── TOSCA-Metadata │ │ │ │ │ └── TOSCA.meta │ │ │ ├── test_vnf_package.py │ │ │ ├── test_vnflcm.py │ │ │ ├── test_vnflcm_op_occs.py │ │ │ ├── test_vnflcm_subsc.py │ │ │ ├── vnf_package_fakes.py │ │ │ ├── vnflcm_fakes.py │ │ │ ├── vnflcm_op_occs_fakes.py │ │ │ └── vnflcm_subsc_fakes.py │ │ └── v2 │ │ │ ├── __init__.py │ │ │ ├── test_vnffm_alarm.py │ │ │ ├── test_vnffm_sub.py │ │ │ ├── test_vnflcm.py │ │ │ ├── test_vnfpm_job.py │ │ │ ├── test_vnfpm_report.py │ │ │ ├── test_vnfpm_threshold.py │ │ │ ├── vnffm_alarm_fakes.py │ │ │ ├── vnffm_sub_fakes.py │ │ │ ├── vnfpm_job_fakes.py │ │ │ ├── vnfpm_report_fakes.py │ │ │ └── vnfpm_threshold_fakes.py │ │ ├── test_auth.py │ │ ├── test_casual_args.py │ │ ├── test_cli10.py │ │ ├── test_command_meta.py │ │ ├── test_http.py │ │ ├── test_shell.py │ │ ├── test_ssl.py │ │ ├── test_utils.py │ │ ├── test_validators.py │ │ └── vm │ │ ├── __init__.py │ │ ├── samples │ │ ├── vim_config.yaml │ │ ├── vim_config_with_false_cert_verify.yaml │ │ ├── vim_config_without_auth_url.yaml │ │ ├── vim_k8s_bearer_token.yaml │ │ ├── vim_k8s_bearer_token_without_auth_url.yaml │ │ ├── vim_k8s_config.yaml │ │ └── vim_k8s_config_without_auth_url.yaml │ │ ├── test_cli10_vim.py │ │ ├── test_cli10_vim_k8s.py │ │ ├── test_cli10_vim_k8s_with_bearer_token.py │ │ └── test_vim_utils.py ├── v1_0 │ ├── __init__.py │ └── client.py └── version.py ├── test-requirements.txt ├── tools └── tacker.bash_completion └── tox.ini /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | source = tackerclient 4 | omit = tackerclient/openstack/*,tackerclient/tests/* 5 | 6 | [report] 7 | ignore_errors = True 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.DS_Store 3 | *.egg 4 | *.sw? 5 | AUTHORS 6 | ChangeLog 7 | build/* 8 | build-stamp 9 | cover/* 10 | doc/build/ 11 | doc/source/api/ 12 | python_tackerclient.egg-info/* 13 | tacker/vcsversion.py 14 | tackerclient/versioninfo 15 | run_tests.err.log 16 | run_tests.log 17 | .autogenerated 18 | .coverage 19 | .testrepository/ 20 | .idea/ 21 | .tox/ 22 | .venv/ 23 | .stestr/ 24 | 25 | # Files created by releasenotes build 26 | releasenotes/build 27 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=review.opendev.org 3 | port=29418 4 | project=openstack/python-tackerclient.git 5 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | # The format of this file isn't really documented; just use --generate-rcfile 2 | [MASTER] 3 | # Add to the black list. It should be a base name, not a 4 | # path. You may set this option multiple times. 5 | ignore=test 6 | 7 | [Messages Control] 8 | # NOTE(justinsb): We might want to have a 2nd strict pylintrc in future 9 | # C0111: Don't require docstrings on every method 10 | # W0511: TODOs in code comments are fine. 11 | # W0142: *args and **kwargs are fine. 12 | # W0622: Redefining id is fine. 13 | disable=C0111,W0511,W0142,W0622 14 | 15 | [Basic] 16 | # Variable names can be 1 to 31 characters long, with lowercase and underscores 17 | variable-rgx=[a-z_][a-z0-9_]{0,30}$ 18 | 19 | # Argument names can be 2 to 31 characters long, with lowercase and underscores 20 | argument-rgx=[a-z_][a-z0-9_]{1,30}$ 21 | 22 | # Method names should be at least 3 characters long 23 | # and be lowecased with underscores 24 | method-rgx=([a-z_][a-z0-9_]{2,50}|setUp|tearDown)$ 25 | 26 | # Module names matching quantum-* are ok (files in bin/) 27 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|(quantum-[a-z0-9_-]+))$ 28 | 29 | # Don't require docstrings on tests. 30 | no-docstring-rgx=((__.*__)|([tT]est.*)|setUp|tearDown)$ 31 | 32 | [Design] 33 | max-public-methods=100 34 | min-public-methods=0 35 | max-args=6 36 | 37 | [Variables] 38 | 39 | # List of additional names supposed to be defined in builtins. Remember that 40 | # you should avoid to define new builtins when possible. 41 | # _ is used by our localization 42 | additional-builtins=_ 43 | -------------------------------------------------------------------------------- /.stestr.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | test_path=./tackerclient/tests/unit 3 | top_path=./ 4 | -------------------------------------------------------------------------------- /.zuul.yaml: -------------------------------------------------------------------------------- 1 | - project: 2 | templates: 3 | - check-requirements 4 | - openstack-python3-jobs 5 | - publish-openstack-docs-pti 6 | - release-notes-jobs-python3 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | If you would like to contribute to the development of OpenStack, 2 | you must follow the steps in this page: 3 | 4 | https://docs.openstack.org/infra/manual/developers.html 5 | 6 | Once those steps have been completed, changes to OpenStack 7 | should be submitted for review via the Gerrit tool, following 8 | the workflow documented at: 9 | 10 | https://docs.openstack.org/infra/manual/developers.html#development-workflow 11 | 12 | Pull requests submitted through GitHub will be ignored. 13 | 14 | Bugs should be filed on Launchpad, not GitHub: 15 | 16 | https://bugs.launchpad.net/python-tackerclient 17 | -------------------------------------------------------------------------------- /HACKING.rst: -------------------------------------------------------------------------------- 1 | Tacker Style Commandments 2 | ========================= 3 | 4 | - Step 1: Read the OpenStack Style Commandments 5 | https://docs.openstack.org/hacking/latest 6 | - Step 2: Read on 7 | 8 | 9 | Running Tests 10 | ------------- 11 | The testing system is based on a combination of tox and stestr. The canonical 12 | approach to running tests is to simply run the command ``tox``. This will 13 | create virtual environments, populate them with dependencies and run all of 14 | the tests that OpenStack CI systems run. Behind the scenes, tox is running 15 | ``stestr run``, but is set up such that you can supply any additional 16 | stestr arguments that are needed to tox. For example, you can run: 17 | ``tox -- --analyze-isolation`` to cause tox to tell stestr to add 18 | --analyze-isolation to its argument list. 19 | 20 | It is also possible to run the tests inside of a virtual environment 21 | you have created, or it is possible that you have all of the dependencies 22 | installed locally already. In this case, you can interact with the stestr 23 | command directly. Running ``stestr run`` will run the entire test suite. 24 | ``stestr run --concurrency=1`` will run tests serially (by default, stestr runs 25 | tests in parallel). More information about stestr can be found at: 26 | http://stestr.readthedocs.io/ 27 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include tox.ini 2 | include LICENSE README.rst HACKING.rst 3 | include AUTHORS 4 | include ChangeLog 5 | include tools/* 6 | recursive-include tests * 7 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Team and repository tags 3 | ======================== 4 | 5 | .. image:: https://governance.openstack.org/tc/badges/python-tackerclient.svg 6 | :target: https://governance.openstack.org/tc/reference/tags/index.html 7 | 8 | .. Change things from this point on 9 | 10 | NFV Orchestration (Tacker) Client 11 | ================================= 12 | 13 | CLI and Client Library for OpenStack Tacker 14 | 15 | Installation 16 | ============ 17 | 18 | **Note:** The paths we are using for configuration files in these steps 19 | are with reference to Ubuntu Operating System. The paths may vary for 20 | other Operating Systems. 21 | 22 | The branch_name which is used in commands, specify the branch_name 23 | as stable/ for any stable branch installation. For eg: 24 | stable/queens, stable/pike. If unspecified the default will be 25 | master branch. 26 | 27 | Using python install 28 | -------------------- 29 | Clone python-tackerclient repository. 30 | 31 | :: 32 | 33 | $ cd ~/ 34 | $ git clone https://github.com/openstack/python-tackerclient -b 35 | 36 | 37 | Install python-tackerclient. 38 | 39 | :: 40 | 41 | $ cd python-tackerclient 42 | $ sudo python setup.py install 43 | 44 | 45 | Using pip 46 | --------- 47 | 48 | You can also install the latest version by using ``pip`` command: 49 | 50 | :: 51 | 52 | $ pip install python-tackerclient 53 | 54 | 55 | Or, if it is needed to install ``python-tackerclient`` from master branch, 56 | type 57 | 58 | :: 59 | 60 | $ pip install git+https://github.com/openstack/python-tackerclient.git 61 | 62 | 63 | More Information 64 | ================ 65 | 66 | * Python-tackerclient documentation: https://docs.openstack.org/python-tackerclient/latest/ 67 | * Tacker Documentation: https://docs.openstack.org/tacker/latest/ 68 | * Tacker Wiki: https://wiki.openstack.org/wiki/Tacker 69 | * Release Notes: https://docs.openstack.org/releasenotes/python-tackerclient 70 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | # The order of packages is significant, because pip processes them in the order 2 | # of appearance. Changing the order has an impact on the overall integration 3 | # process, which may cause wedges in the gate later. 4 | # These are needed for docs generation 5 | sphinx>=2.0.0,!=2.1.0 # BSD 6 | openstackdocstheme>=2.2.1 # Apache-2.0 7 | reno>=3.1.0 # Apache-2.0 8 | -------------------------------------------------------------------------------- /doc/source/cli/commands.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ============= 15 | Command List 16 | ============= 17 | 18 | The following list covers the extended commands for Tacker services 19 | available in **openstack** command. 20 | 21 | These commands can be referenced by doing **openstack help** and the detail 22 | of individual command can be referred by **openstack help **. 23 | 24 | .. code-block:: console 25 | 26 | [legacy] 27 | openstack vim list List VIM(s) that belong to a given tenant. 28 | openstack vim register Create a VIM. 29 | openstack vim show Show information of a given VIM. 30 | openstack vim set Update a given VIM. 31 | openstack vim delete Delete given VIM(s). 32 | 33 | [v1] --os-tacker-api-version 1 34 | openstack vnf package create Create a new individual VNF package resource. 35 | openstack vnf package delete Delete given VNF package(s). 36 | openstack vnf package list List all VNF packages. 37 | openstack vnf package show Show package details. 38 | openstack vnf package upload Upload a VNF package. 39 | openstack vnf package download Download a VNF package. 40 | openstack vnf package artifact download Download a VNF package artifact. 41 | openstack vnf package update Update a state of a VNF package. 42 | openstack vnflcm create Create a new VNF instance resource. 43 | openstack vnflcm instantiate Instantiate a VNF instance. 44 | openstack vnflcm list List VNF instance. 45 | openstack vnflcm show Show VNF instance. 46 | openstack vnflcm terminate Terminate a VNF instance. 47 | openstack vnflcm delete Delete a VNF instance resource. 48 | openstack vnflcm heal Heal a VNF instance. 49 | openstack vnflcm update Update information of a VNF instance. 50 | openstack vnflcm scale Scale a VNF instance. 51 | openstack vnflcm change-ext-conn Change external VNF connectivity. 52 | openstack vnflcm op rollback Rollback a VNF LCM operation occurrence. 53 | openstack vnflcm op retry Retry a VNF LCM operation occurrence. 54 | openstack vnflcm op fail Fail a VNF LCM operation occurrence. 55 | openstack vnflcm op list List VNF LCM operation occurrence. 56 | openstack vnflcm op show Show VNF LCM operation occurrence. 57 | openstack vnflcm op cancel Cancel a VNF LCM operation occurrence. 58 | openstack vnflcm versions Show VNF LCM API versions. 59 | openstack vnflcm subsc create Create new subscription. 60 | openstack vnflcm subsc delete Delete subscription. 61 | openstack vnflcm subsc list List subscription. 62 | openstack vnflcm subsc show Show subscription. 63 | 64 | [v2] --os-tacker-api-version 2 65 | openstack vnflcm create Create a new VNF instance resource. 66 | openstack vnflcm instantiate Instantiate a VNF instance. 67 | openstack vnflcm list List VNF instance. 68 | openstack vnflcm show Show VNF instance. 69 | openstack vnflcm terminate Terminate a VNF instance. 70 | openstack vnflcm delete Delete a VNF instance resource. 71 | openstack vnflcm heal Heal a VNF instance. 72 | openstack vnflcm update Update information of a VNF instance. 73 | openstack vnflcm scale Scale a VNF instance. 74 | openstack vnflcm change-ext-conn Change external VNF connectivity. 75 | openstack vnflcm change-vnfpkg Change current VNF package. 76 | openstack vnflcm op rollback Rollback a VNF LCM operation occurrence. 77 | openstack vnflcm op retry Retry a VNF LCM operation occurrence. 78 | openstack vnflcm op fail Fail a VNF LCM operation occurrence. 79 | openstack vnflcm op list List VNF LCM operation occurrence. 80 | openstack vnflcm op show Show VNF LCM operation occurrence. 81 | openstack vnflcm versions Show VNF LCM API versions. 82 | openstack vnflcm subsc create Create new subscription. 83 | openstack vnflcm subsc delete Delete subscription. 84 | openstack vnflcm subsc list List subscription. 85 | openstack vnflcm subsc show Show subscription. 86 | openstack vnffm alarm list List alarm. 87 | openstack vnffm alarm show Show alarm. 88 | openstack vnffm alarm update Update alarm. 89 | openstack vnffm sub create Create FM subscription. 90 | openstack vnffm sub list List FM subscription. 91 | openstack vnffm sub show Show FM subscription. 92 | openstack vnffm sub delete Delete FM subscription. 93 | openstack vnfpm job create Create PM job. 94 | openstack vnfpm job list List PM job. 95 | openstack vnfpm job show Show PM job. 96 | openstack vnfpm job update Update PM job. 97 | openstack vnfpm job delete Delete PM job. 98 | openstack vnfpm report show Show PM report. 99 | openstack vnfpm threshold create Create PM threshold. 100 | openstack vnfpm threshold list List PM threshold. 101 | openstack vnfpm threshold show Show PM threshold. 102 | openstack vnfpm threshold update Update PM threshold. 103 | openstack vnfpm threshold delete Delete PM threshold. 104 | -------------------------------------------------------------------------------- /doc/source/cli/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ========= 15 | CLI Usage 16 | ========= 17 | 18 | Command List 19 | ------------ 20 | 21 | .. toctree:: 22 | 23 | commands 24 | 25 | Operations for ETSI NFV-SOL implementation 26 | ------------------------------------------ 27 | 28 | .. toctree:: 29 | 30 | vnf_package_commands 31 | vnflcm_commands 32 | vnffm_commands 33 | vnfpm_commands 34 | 35 | Operations for Legacy implementation 36 | ------------------------------------ 37 | 38 | .. toctree:: 39 | 40 | vim_commands 41 | -------------------------------------------------------------------------------- /doc/source/cli/vim_commands.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ======================= 15 | VIM Management commands 16 | ======================= 17 | 18 | .. autoprogram-cliff:: openstack.tackerclient.v1 19 | :command: vim * 20 | -------------------------------------------------------------------------------- /doc/source/cli/vnf_package_commands.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ==================== 15 | VNF Package commands 16 | ==================== 17 | 18 | VNF Package commands are CLI interface of VNF Package Management Interface in 19 | `ETSI NFV-SOL 005 `_. 20 | 21 | .. autoprogram-cliff:: openstack.tackerclient.v1 22 | :command: vnf package * 23 | -------------------------------------------------------------------------------- /doc/source/cli/vnffm_commands.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | =============== 15 | VNF FM commands 16 | =============== 17 | 18 | VNF FM commands are CLI interface of VNF Fault Management interface in 19 | `ETSI NFV-SOL 002 `_ 20 | and `ETSI NFV-SOL 003 `_. 21 | 22 | .. note:: 23 | Commands only support calling version 2 vnffm APIs. 24 | You can use the commands with **\-\-os-tacker-api-version 2** to 25 | call version 2 vnffm APIs. 26 | 27 | .. autoprogram-cliff:: openstack.tackerclient.v2 28 | :command: vnffm * 29 | -------------------------------------------------------------------------------- /doc/source/cli/vnflcm_commands.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ================ 15 | VNF Lcm commands 16 | ================ 17 | 18 | VNF LCM commands are CLI interface of VNF Lifecycle Management Interface in 19 | `ETSI NFV-SOL 002 `_ 20 | and `ETSI NFV-SOL 003 `_. 21 | 22 | .. note:: 23 | Commands call version 1 vnflcm APIs by default. 24 | You can call the specific version of vnflcm APIs 25 | by using the option **\-\-os-tacker-api-version**. 26 | Commands with **\-\-os-tacker-api-version 2** call version 2 vnflcm APIs. 27 | **vnflcm op cancel** is included in only version 1 vnflcm APIs 28 | and **change-vnfpkg** is included in only version 2 vnflcm APIs. 29 | 30 | .. autoprogram-cliff:: openstack.tackerclient.v1 31 | :command: vnflcm * 32 | 33 | .. autoprogram-cliff:: openstack.tackerclient.v2 34 | :command: vnflcm change-vnfpkg 35 | -------------------------------------------------------------------------------- /doc/source/cli/vnfpm_commands.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | =============== 15 | VNF PM commands 16 | =============== 17 | 18 | VNF PM commands are CLI interface of VNF Performance Management interface in 19 | `ETSI NFV-SOL 002 `_ 20 | and `ETSI NFV-SOL 003 `_. 21 | 22 | .. note:: 23 | Commands only support calling version 2 vnfpm APIs. 24 | You can use the commands with **\-\-os-tacker-api-version 2** to 25 | call version 2 vnfpm APIs. 26 | 27 | .. autoprogram-cliff:: openstack.tackerclient.v2 28 | :command: vnfpm * 29 | -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | # not use this file except in compliance with the License. You may obtain 4 | # a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | # License for the specific language governing permissions and limitations 12 | # under the License. 13 | 14 | # python-tackerclient documentation build configuration file 15 | 16 | import os 17 | import sys 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | # sys.path.append(os.path.abspath('.')) 23 | 24 | sys.path.insert(0, os.path.abspath('../..')) 25 | 26 | # -- General configuration ---------------------------------------------------- 27 | 28 | # Add any Sphinx extension module names here, as strings. They can be 29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 30 | extensions = [ 31 | 'sphinx.ext.autodoc', 32 | 'reno.sphinxext', 33 | 'openstackdocstheme', 34 | 'cliff.sphinxext', 35 | ] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # The suffix of source filenames. 41 | source_suffix = '.rst' 42 | 43 | # The master toctree document. 44 | master_doc = 'index' 45 | 46 | # General information about the project. 47 | copyright = 'OpenStack Contributors' 48 | 49 | # If true, '()' will be appended to :func: etc. cross-reference text. 50 | add_function_parentheses = True 51 | 52 | # If true, the current module name will be prepended to all description 53 | # unit titles (such as .. function::). 54 | add_module_names = True 55 | 56 | # The name of the Pygments (syntax highlighting) style to use. 57 | pygments_style = 'native' 58 | 59 | # -- Options for HTML output -------------------------------------------------- 60 | 61 | # The theme to use for HTML and HTML Help pages. Major themes that come with 62 | # Sphinx are currently 'default' and 'sphinxdoc'. 63 | html_theme = 'openstackdocs' 64 | 65 | # Output file base name for HTML help builder. 66 | htmlhelp_basename = 'tackerclientdoc' 67 | 68 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 69 | # using the given strftime format. 70 | 71 | # -- Options for manual page output ------------------------------------------- 72 | 73 | man_pages = [ 74 | ('cli/index', 'tacker', 'Client for Tacker API', 75 | ['OpenStack Contributors'], 1), 76 | ] 77 | 78 | # -- Options for openstackdocstheme ------------------------------------------- 79 | 80 | openstackdocs_repo_name = 'openstack/python-tackerclient' 81 | openstackdocs_bug_project = 'python-tackerclient' 82 | openstackdocs_bug_tag = 'doc' 83 | 84 | # -- Options for cliff.sphinxext plugin --------------------------------------- 85 | 86 | autoprogram_cliff_application = 'openstack' 87 | -------------------------------------------------------------------------------- /doc/source/contributor/contributing.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ============ 15 | Contributing 16 | ============ 17 | 18 | .. include:: ../../../CONTRIBUTING.rst 19 | -------------------------------------------------------------------------------- /doc/source/contributor/developing.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | =================================== 15 | Developing with Python-TackerClient 16 | =================================== 17 | 18 | Project Info 19 | ============ 20 | 21 | * **Free software:** under the `Apache license `_ 22 | * **Tacker Service:** https://opendev.org/openstack/tacker 23 | * **Tacker Client Library:** https://opendev.org/openstack/python-tackerclient 24 | * **Tacker Service Bugs:** https://bugs.launchpad.net/tacker 25 | * **Client Bugs:** https://bugs.launchpad.net/python-tackerclient 26 | * **Blueprints:** https://blueprints.launchpad.net/tacker 27 | 28 | Meetings 29 | ======== 30 | For details please refer to the `OpenStack IRC meetings`_ page. 31 | 32 | .. _`OpenStack IRC meetings`: http://eavesdrop.openstack.org/#Tacker_(NFV_Orchestrator_and_VNF_Manager)_Team_Meeting 33 | 34 | Testing 35 | ======= 36 | 37 | For details please refer to the `Developing with OpenStackClient`_ page. 38 | 39 | .. _`Developing with OpenStackClient`: https://docs.openstack.org/python-openstackclient/latest/contributor/developing.html -------------------------------------------------------------------------------- /doc/source/contributor/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ================= 15 | Contributor Guide 16 | ================= 17 | 18 | In the Contributor Guide, you will find information on tackerclient's 19 | lower level programming details or APIs as well as the transition to 20 | OpenStack client. 21 | 22 | .. toctree:: 23 | :maxdepth: 2 24 | 25 | contributing.rst 26 | developing.rst 27 | 28 | 29 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ================================= 15 | Python-TackerClient Documentation 16 | ================================= 17 | 18 | Python-TackerClient is a client for OpenStack NFV MANO (Tacker) API. 19 | It provides 20 | :doc:`Python API bindings ` (the tackerclient module) and 21 | :doc:`command-line interface (CLI) `. 22 | 23 | Contents 24 | -------- 25 | 26 | .. toctree:: 27 | :maxdepth: 2 28 | 29 | install/index 30 | cli/index 31 | contributor/index 32 | reference/index 33 | 34 | 35 | Release Notes 36 | ------------- 37 | 38 | .. toctree:: 39 | :maxdepth: 1 40 | 41 | Release Notes 42 | 43 | 44 | Indices and Tables 45 | ------------------ 46 | 47 | * :ref:`genindex` 48 | * :ref:`search` 49 | -------------------------------------------------------------------------------- /doc/source/install/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ============ 15 | Installation 16 | ============ 17 | 18 | This document describes how to install python-tackerclient. 19 | 20 | .. note:: 21 | 22 | This installation guide contents are specific to Ubuntu distro. 23 | 24 | Using python install 25 | ==================== 26 | 27 | #. Clone python-tackerclient repository. 28 | 29 | You can use -b for specific release, optionally. 30 | 31 | .. code-block:: console 32 | 33 | $ cd ~/ 34 | $ git clone https://opendev.org/openstack/python-tackerclient -b 35 | 36 | .. note:: 37 | 38 | Make sure to replace the ```` in command example with 39 | specific branch name, such as ``stable/victoria``. 40 | 41 | #. Install python-tackerclient. 42 | 43 | .. code-block:: console 44 | 45 | $ cd python-tackerclient 46 | $ sudo python3 setup.py install 47 | 48 | Using pip 49 | ========= 50 | 51 | You can also install the latest version by using ``pip`` command: 52 | 53 | .. code-block:: console 54 | 55 | $ pip3 install python-tackerclient 56 | 57 | Or, if it is needed to install ``python-tackerclient`` from master branch, 58 | type 59 | 60 | .. code-block:: console 61 | 62 | $ pip3 install git+https://opendev.org/openstack/python-tackerclient 63 | 64 | -------------------------------------------------------------------------------- /doc/source/reference/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | ========= 15 | Reference 16 | ========= 17 | 18 | - `Tacker API reference `_ 19 | - `Tacker CLI reference `_ -------------------------------------------------------------------------------- /releasenotes/notes/add-creating-ns-vnffg-from-template-213eee7f1820aa0c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Support to create directly VNFFG and NS from its descriptor template 5 | without creating VNFFGD and NSD. -------------------------------------------------------------------------------- /releasenotes/notes/add-vnffg-and-vnf-ids-to-ns-list-commands-9d462efc103f8ecb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Add 'vnf_ids' and 'vnffg_ids' fields in outputs from network 5 | service list command. Users can know which VNFs or VNFFGs, 6 | belongs to specific NS. 7 | Add 'ns_id' field to VNFFG list command, that shows the 8 | network service the current VNFFG belongs to. 9 | 10 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1750865-04c3ebd0c3f8af29.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | The VNFFGD CLI cannot show the VNFFGD template. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1754556-53268d3081fa18d1.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Add documentation for python-tackerclient. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1754793-54446bcd0a4e84aa.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Fix the VNFFG update osc command misusing create_vnffg function. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1754926-06ac4d7ffd17b5ce.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Fix local test fail with pypy. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/clustering-service-cli-e15cc6627de293fa.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Enable CLI to support clustering service in Tacker Server. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/del-project_and_user_id-e9dd396f83a162d6.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - 4 | As user gives input of project and user name in vim_config.yaml, 5 | delete the user and project id from the vim specific commands 6 | output. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/deprecate-direct-yaml-cli-input-812564bab1b99b4b.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | deprecations: 3 | - | 4 | Direct YAML input of any kind is now deprecated. Only file based YAML 5 | input is supported. This deprecation is across all resources like VNFFGD 6 | template, VNFD template and VNF configuration input. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/deprecate-infra-mgmt-driver-attributes-e371624c50accee8.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | deprecations: 3 | - infra_driver and mgmt_driver attributes in VNFD client 4 | attribute is deprecated and will be removed in Ocata. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/deprecate-legacy-apis-excluding-vim-debaa69507f73179.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | deprecations: 3 | - | 4 | Legacy APIs excluding VIM feature are deprecated and will be removed in the 5 | first major release after the Tacker server version 9.0.0 (2023.1 Antelope 6 | release). 7 | -------------------------------------------------------------------------------- /releasenotes/notes/deprecated-tacker-command-29121558bd748082.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | deprecations: 3 | - | 4 | tacker CLI is deprecated, will be deleted after Rocky release. 5 | Use `openstack CLI`_ instead. 6 | 7 | .. _openstack CLI: https://docs.openstack.org/python-tackerclient/latest/cli/index.html 8 | -------------------------------------------------------------------------------- /releasenotes/notes/drop-py-2-7-b2052825c4b92b52.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Python 2.7 support has been dropped. Last release of python-tackerclient 5 | to support python 2.7 is OpenStack Train. The minimum version of Python now 6 | supported by python-tackerclient is Python 3.6. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/multi-delete-support-in-tacker-acd4a7e86114f0be.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add support for multi delete feature for resources. 4 | -------------------------------------------------------------------------------- /releasenotes/notes/network-services-descriptor-06f6abe90adb40f3.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | CLIs to onboard Network Services Descriptor (NSD) based on TOSCA Simple 5 | Profile for NFV and to create Network Services using NSD to create multiple 6 | related VNFs using a single TOSCA template. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/new-commmand-vnf-resource-list-d5422ab917f0892f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Adds new CLI command 'vnf-resource-list' to view VNF 4 | resources, such as VDU, CP, etc. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/obsolete-legacy-apis-excluding-vim-43d8dd73c3768fbb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Legacy APIs excluding VIM feature are obsoleted. -------------------------------------------------------------------------------- /releasenotes/notes/remove-passing-mgmt-and-infra-driver-from-client-c9135f84480b2cae.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - Remove passing mgmt and infra driver from client. 4 | -------------------------------------------------------------------------------- /releasenotes/notes/tacker-support-python-openstackclient-b88b20b80b872229.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Add python-vnfd, vnf, nsd, ns, vnffgd, vnffg, event commands support. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/update-vim-without-config-c3b637741889eff6.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - VIM can be updated without config-file argument in tacker vim-update command. 4 | -------------------------------------------------------------------------------- /releasenotes/notes/vnf-inline-template-25f6a0b66f7407a1.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Support to create VNF with direct VNFD template input from CLI. 4 | -------------------------------------------------------------------------------- /releasenotes/notes/vnfd-vnf-vim-name-mandatory-in-tacker-cli-dfe802af6de5c80e.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Made VNFD/VNF/VIM names mandatory in tacker CLI. 4 | -------------------------------------------------------------------------------- /releasenotes/notes/vnffg-client-abd7d7f06860b91d.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add client support for VNFFG. 4 | -------------------------------------------------------------------------------- /releasenotes/source/2023.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2023.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/2023.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/2023.2.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2023.2 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2023.2 7 | -------------------------------------------------------------------------------- /releasenotes/source/2024.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2024.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2024.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/2024.2.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2024.2 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2024.2 7 | -------------------------------------------------------------------------------- /releasenotes/source/2025.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2025.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2025.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/_static/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/releasenotes/source/_static/.placeholder -------------------------------------------------------------------------------- /releasenotes/source/_templates/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/releasenotes/source/_templates/.placeholder -------------------------------------------------------------------------------- /releasenotes/source/index.rst: -------------------------------------------------------------------------------- 1 | Python-TackerClient Release Notes 2 | ================================= 3 | 4 | Contents: 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | unreleased 10 | 2025.1 11 | 2024.2 12 | 2024.1 13 | 2023.2 14 | 2023.1 15 | zed 16 | yoga 17 | xena 18 | wallaby 19 | victoria 20 | ussuri 21 | train 22 | stein 23 | rocky 24 | queens 25 | pike 26 | ocata 27 | newton 28 | -------------------------------------------------------------------------------- /releasenotes/source/newton.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Newton Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: origin/stable/newton 7 | -------------------------------------------------------------------------------- /releasenotes/source/ocata.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Ocata Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: origin/stable/ocata 7 | -------------------------------------------------------------------------------- /releasenotes/source/pike.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Pike Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/pike 7 | -------------------------------------------------------------------------------- /releasenotes/source/queens.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Queens Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/queens 7 | -------------------------------------------------------------------------------- /releasenotes/source/rocky.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Rocky Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/rocky 7 | -------------------------------------------------------------------------------- /releasenotes/source/stein.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Stein Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/stein 7 | -------------------------------------------------------------------------------- /releasenotes/source/train.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Train Series Release Notes 3 | ========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/train 7 | -------------------------------------------------------------------------------- /releasenotes/source/unreleased.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Current Series Release Notes 3 | ============================ 4 | 5 | .. release-notes:: 6 | -------------------------------------------------------------------------------- /releasenotes/source/ussuri.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | Ussuri Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/ussuri 7 | -------------------------------------------------------------------------------- /releasenotes/source/victoria.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | Victoria Series Release Notes 3 | ============================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/victoria 7 | -------------------------------------------------------------------------------- /releasenotes/source/wallaby.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Wallaby Series Release Notes 3 | ============================ 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/wallaby 7 | -------------------------------------------------------------------------------- /releasenotes/source/xena.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Xena Series Release Notes 3 | ========================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/xena 7 | -------------------------------------------------------------------------------- /releasenotes/source/yoga.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Yoga Series Release Notes 3 | ========================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/yoga 7 | -------------------------------------------------------------------------------- /releasenotes/source/zed.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Zed Series Release Notes 3 | ======================== 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/zed 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # The order of packages is significant, because pip processes them in the order 2 | # of appearance. Changing the order has an impact on the overall integration 3 | # process, which may cause wedges in the gate later. 4 | pbr!=2.1.0,>=2.0.0 # Apache-2.0 5 | cliff!=2.9.0,>=2.8.0 # Apache-2.0 6 | iso8601>=0.1.11 # MIT 7 | netaddr>=0.7.18 # BSD 8 | requests>=2.14.2 # Apache-2.0 9 | python-keystoneclient>=3.8.0 # Apache-2.0 10 | stevedore>=1.20.0 # Apache-2.0 11 | Babel!=2.4.0,>=2.3.4 # BSD 12 | oslo.i18n>=3.15.3 # Apache-2.0 13 | osc-lib>=1.8.0 # Apache-2.0 14 | oslo.utils>=3.40.0 # Apache-2.0 15 | oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 16 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import setuptools 17 | 18 | setuptools.setup( 19 | setup_requires=['pbr>=2.0.0'], 20 | pbr=True) 21 | -------------------------------------------------------------------------------- /tackerclient/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/__init__.py -------------------------------------------------------------------------------- /tackerclient/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/common/__init__.py -------------------------------------------------------------------------------- /tackerclient/common/_i18n.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 OpenStack Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | """oslo.i18n integration module. 16 | 17 | See https://docs.openstack.org/oslo.i18n/latest/user/index.html. 18 | 19 | """ 20 | 21 | import oslo_i18n 22 | 23 | DOMAIN = "tackerclient" 24 | 25 | _translators = oslo_i18n.TranslatorFactory(domain=DOMAIN) 26 | 27 | # The primary translation function using the well-known name "_" 28 | _ = _translators.primary 29 | 30 | # The contextual translation function using the name "_C" 31 | # requires oslo.i18n >=2.1.0 32 | _C = _translators.contextual_form 33 | 34 | # The plural translation function using the name "_P" 35 | # requires oslo.i18n >=2.1.0 36 | _P = _translators.plural_form 37 | 38 | 39 | def get_available_languages(): 40 | return oslo_i18n.get_available_languages(DOMAIN) 41 | -------------------------------------------------------------------------------- /tackerclient/common/clientmanager.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 OpenStack Foundation. 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | # 16 | 17 | """Manage access to the clients, including authenticating when needed. 18 | """ 19 | 20 | from tackerclient import client 21 | from tackerclient.tacker import client as tacker_client 22 | 23 | 24 | class ClientCache(object): 25 | """Descriptor class for caching created client handles.""" 26 | 27 | def __init__(self, factory): 28 | self.factory = factory 29 | self._handle = None 30 | 31 | def __get__(self, instance, owner): 32 | # Tell the ClientManager to login to keystone 33 | if self._handle is None: 34 | self._handle = self.factory(instance) 35 | return self._handle 36 | 37 | 38 | class ClientManager(object): 39 | """Manages access to API clients, including authentication.""" 40 | tacker = ClientCache(tacker_client.make_client) 41 | 42 | def __init__(self, token=None, url=None, 43 | auth_url=None, 44 | endpoint_type=None, 45 | tenant_name=None, 46 | tenant_id=None, 47 | username=None, 48 | user_id=None, 49 | password=None, 50 | region_name=None, 51 | api_version=None, 52 | auth_strategy=None, 53 | insecure=False, 54 | ca_cert=None, 55 | log_credentials=False, 56 | service_type=None, 57 | timeout=None, 58 | retries=0, 59 | raise_errors=True, 60 | session=None, 61 | auth=None, 62 | ): 63 | self._token = token 64 | self._url = url 65 | self._auth_url = auth_url 66 | self._service_type = service_type 67 | self._endpoint_type = endpoint_type 68 | self._tenant_name = tenant_name 69 | self._tenant_id = tenant_id 70 | self._username = username 71 | self._user_id = user_id 72 | self._password = password 73 | self._region_name = region_name 74 | self._api_version = api_version 75 | self._service_catalog = None 76 | self._auth_strategy = auth_strategy 77 | self._insecure = insecure 78 | self._ca_cert = ca_cert 79 | self._log_credentials = log_credentials 80 | self._timeout = timeout 81 | self._retries = retries 82 | self._raise_errors = raise_errors 83 | self._session = session 84 | self._auth = auth 85 | return 86 | 87 | def initialize(self): 88 | if not self._url: 89 | httpclient = client.construct_http_client( 90 | username=self._username, 91 | user_id=self._user_id, 92 | tenant_name=self._tenant_name, 93 | tenant_id=self._tenant_id, 94 | password=self._password, 95 | region_name=self._region_name, 96 | auth_url=self._auth_url, 97 | service_type=self._service_type, 98 | endpoint_type=self._endpoint_type, 99 | insecure=self._insecure, 100 | ca_cert=self._ca_cert, 101 | timeout=self._timeout, 102 | session=self._session, 103 | auth=self._auth, 104 | log_credentials=self._log_credentials) 105 | httpclient.authenticate() 106 | # Populate other password flow attributes 107 | self._token = httpclient.auth_token 108 | self._url = httpclient.endpoint_url 109 | -------------------------------------------------------------------------------- /tackerclient/common/command.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 OpenStack Foundation. 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | # 16 | 17 | from sys import stderr 18 | 19 | from cliff import command 20 | 21 | 22 | class OpenStackCommand(command.Command): 23 | """Base class for OpenStack commands.""" 24 | 25 | api = None 26 | 27 | def run(self, parsed_args): 28 | stderr.write("Deprecated: tacker command line is deprecated, " 29 | "will be deleted after Rocky is released.\n") 30 | if not self.api: 31 | return 32 | else: 33 | return super(OpenStackCommand, self).run(parsed_args) 34 | 35 | def get_data(self, parsed_args): 36 | pass 37 | 38 | def take_action(self, parsed_args): 39 | return self.get_data(parsed_args) 40 | -------------------------------------------------------------------------------- /tackerclient/common/constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2012 OpenStack Foundation. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | TYPE_BOOL = "bool" 18 | TYPE_INT = "int" 19 | TYPE_FLOAT = "float" 20 | TYPE_LIST = "list" 21 | TYPE_DICT = "dict" 22 | -------------------------------------------------------------------------------- /tackerclient/common/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 VMware, Inc 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from tackerclient.i18n import _ 17 | 18 | """ 19 | Tacker base exception handling. 20 | 21 | Exceptions are classified into three categories: 22 | * Exceptions corresponding to exceptions from tacker server: 23 | This type of exceptions should inherit one of exceptions 24 | in HTTP_EXCEPTION_MAP. 25 | * Exceptions from client library: 26 | This type of exceptions should inherit TackerClientException. 27 | * Exceptions from CLI code: 28 | This type of exceptions should inherit TackerCLIError. 29 | """ 30 | 31 | 32 | class TackerException(Exception): 33 | """Base Tacker Exception. 34 | 35 | To correctly use this class, inherit from it and define 36 | a 'message' property. That message will get printf'd 37 | with the keyword arguments provided to the constructor. 38 | """ 39 | message = _("An unknown exception occurred.") 40 | 41 | def __init__(self, message=None, **kwargs): 42 | if message: 43 | self.message = message 44 | try: 45 | self._error_string = self.message % kwargs 46 | except Exception: 47 | # at least get the core message out if something happened 48 | self._error_string = self.message 49 | 50 | def __str__(self): 51 | return self._error_string 52 | 53 | 54 | class TackerClientException(TackerException): 55 | """Base exception which exceptions from Tacker are mapped into. 56 | 57 | NOTE: on the client side, we use different exception types in order 58 | to allow client library users to handle server exceptions in try...except 59 | blocks. The actual error message is the one generated on the server side. 60 | """ 61 | 62 | status_code = 0 63 | 64 | def __init__(self, message=None, **kwargs): 65 | if 'status_code' in kwargs: 66 | self.status_code = kwargs['status_code'] 67 | super(TackerClientException, self).__init__(message, **kwargs) 68 | 69 | 70 | # Base exceptions from Tacker 71 | 72 | class BadRequest(TackerClientException): 73 | status_code = 400 74 | 75 | 76 | class Unauthorized(TackerClientException): 77 | status_code = 401 78 | message = _("Unauthorized: bad credentials.") 79 | 80 | 81 | class Forbidden(TackerClientException): 82 | status_code = 403 83 | message = _("Forbidden: your credentials don't give you access to this " 84 | "resource.") 85 | 86 | 87 | class NotFound(TackerClientException): 88 | status_code = 404 89 | 90 | 91 | class Conflict(TackerClientException): 92 | status_code = 409 93 | 94 | 95 | class InternalServerError(TackerClientException): 96 | status_code = 500 97 | 98 | 99 | class ServiceUnavailable(TackerClientException): 100 | status_code = 503 101 | 102 | 103 | HTTP_EXCEPTION_MAP = { 104 | 400: BadRequest, 105 | 401: Unauthorized, 106 | 403: Forbidden, 107 | 404: NotFound, 108 | 409: Conflict, 109 | 500: InternalServerError, 110 | 503: ServiceUnavailable, 111 | } 112 | 113 | 114 | # Exceptions from client library 115 | 116 | class NoAuthURLProvided(Unauthorized): 117 | message = _("auth_url was not provided to the Tacker client") 118 | 119 | 120 | class EndpointNotFound(TackerClientException): 121 | message = _("Could not find Service or Region in Service Catalog.") 122 | 123 | 124 | class EndpointTypeNotFound(TackerClientException): 125 | message = _("Could not find endpoint type %(type_)s in Service Catalog.") 126 | 127 | 128 | class RequestURITooLong(TackerClientException): 129 | """Raised when a request fails with HTTP error 414.""" 130 | 131 | def __init__(self, **kwargs): 132 | self.excess = kwargs.get('excess', 0) 133 | super(RequestURITooLong, self).__init__(**kwargs) 134 | 135 | 136 | class ConnectionFailed(TackerClientException): 137 | message = _("Connection to tacker failed: %(reason)s") 138 | 139 | 140 | class SslCertificateValidationError(TackerClientException): 141 | message = _("SSL certificate validation has failed: %(reason)s") 142 | 143 | 144 | class MalformedResponseBody(TackerClientException): 145 | message = _("Malformed response body: %(reason)s") 146 | 147 | 148 | class InvalidContentType(TackerClientException): 149 | message = _("Invalid content type %(content_type)s.") 150 | 151 | 152 | class InvalidInput(TackerClientException): 153 | message = _("Invalid input: %(reason)s") 154 | 155 | 156 | class EmptyInput(TackerClientException): 157 | message = _("Empty input: %(reason)s") 158 | 159 | 160 | class UnsupportedCommandVersion(TackerClientException): 161 | message = _("This command is not supported in version %(version)s") 162 | 163 | 164 | # Command line exceptions 165 | 166 | class TackerCLIError(TackerException): 167 | """Exception raised when command line parsing fails.""" 168 | pass 169 | 170 | 171 | class CommandError(TackerCLIError): 172 | pass 173 | 174 | 175 | class UnsupportedVersion(TackerCLIError): 176 | """Unsupported Version. 177 | 178 | Indicates that the user is trying to use an unsupported version of 179 | the API. 180 | """ 181 | pass 182 | 183 | 184 | class TackerClientNoUniqueMatch(TackerCLIError): 185 | message = _("Multiple %(resource)s matches found for name '%(name)s'," 186 | " use an ID to be more specific.") 187 | -------------------------------------------------------------------------------- /tackerclient/common/extension.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Rackspace Hosting Inc. 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | # 16 | from stevedore import extension 17 | 18 | from tackerclient.tacker import v1_0 as tackerV10 19 | 20 | 21 | def _discover_via_entry_points(): 22 | emgr = extension.ExtensionManager('tackerclient.extension', 23 | invoke_on_load=False) 24 | return ((ext.name, ext.plugin) for ext in emgr) 25 | 26 | 27 | class TackerClientExtension(tackerV10.TackerCommand): 28 | pagination_support = False 29 | _formatters = {} 30 | sorting_support = False 31 | 32 | 33 | class ClientExtensionShow(TackerClientExtension, tackerV10.ShowCommand): 34 | def get_data(self, parsed_args): 35 | # NOTE(mdietz): Calls 'execute' to provide a consistent pattern 36 | # for any implementers adding extensions with 37 | # regard to any other extension verb. 38 | return self.execute(parsed_args) 39 | 40 | def execute(self, parsed_args): 41 | return super(ClientExtensionShow, self).get_data(parsed_args) 42 | 43 | 44 | class ClientExtensionList(TackerClientExtension, tackerV10.ListCommand): 45 | 46 | def get_data(self, parsed_args): 47 | # NOTE(mdietz): Calls 'execute' to provide a consistent pattern 48 | # for any implementers adding extensions with 49 | # regard to any other extension verb. 50 | return self.execute(parsed_args) 51 | 52 | def execute(self, parsed_args): 53 | return super(ClientExtensionList, self).get_data(parsed_args) 54 | 55 | 56 | class ClientExtensionDelete(TackerClientExtension, tackerV10.DeleteCommand): 57 | def run(self, parsed_args): 58 | # NOTE(mdietz): Calls 'execute' to provide a consistent pattern 59 | # for any implementers adding extensions with 60 | # regard to any other extension verb. 61 | return self.execute(parsed_args) 62 | 63 | def execute(self, parsed_args): 64 | return super(ClientExtensionDelete, self).run(parsed_args) 65 | 66 | 67 | class ClientExtensionCreate(TackerClientExtension, tackerV10.CreateCommand): 68 | def get_data(self, parsed_args): 69 | # NOTE(mdietz): Calls 'execute' to provide a consistent pattern 70 | # for any implementers adding extensions with 71 | # regard to any other extension verb. 72 | return self.execute(parsed_args) 73 | 74 | def execute(self, parsed_args): 75 | return super(ClientExtensionCreate, self).get_data(parsed_args) 76 | 77 | 78 | class ClientExtensionUpdate(TackerClientExtension, tackerV10.UpdateCommand): 79 | def run(self, parsed_args): 80 | # NOTE(mdietz): Calls 'execute' to provide a consistent pattern 81 | # for any implementers adding extensions with 82 | # regard to any other extension verb. 83 | return self.execute(parsed_args) 84 | 85 | def execute(self, parsed_args): 86 | return super(ClientExtensionUpdate, self).run(parsed_args) 87 | -------------------------------------------------------------------------------- /tackerclient/common/serializer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 OpenStack Foundation. 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import logging 17 | 18 | from oslo_serialization import jsonutils 19 | 20 | from tackerclient.common import exceptions as exception 21 | from tackerclient.i18n import _ 22 | 23 | LOG = logging.getLogger(__name__) 24 | 25 | 26 | class ActionDispatcher(object): 27 | """Maps method name to local methods through action name.""" 28 | 29 | def dispatch(self, *args, **kwargs): 30 | """Find and call local method.""" 31 | action = kwargs.pop('action', 'default') 32 | action_method = getattr(self, str(action), self.default) 33 | return action_method(*args, **kwargs) 34 | 35 | def default(self, data): 36 | raise NotImplementedError() 37 | 38 | 39 | class DictSerializer(ActionDispatcher): 40 | """Default request body serialization.""" 41 | 42 | def serialize(self, data, action='default'): 43 | return self.dispatch(data, action=action) 44 | 45 | def default(self, data): 46 | return "" 47 | 48 | 49 | class JSONDictSerializer(DictSerializer): 50 | """Default JSON request body serialization.""" 51 | 52 | def default(self, data): 53 | def sanitizer(obj): 54 | return str(obj) 55 | return jsonutils.dumps(data, default=sanitizer) 56 | 57 | 58 | class TextDeserializer(ActionDispatcher): 59 | """Default request body deserialization.""" 60 | 61 | def deserialize(self, datastring, action='default'): 62 | return self.dispatch(datastring, action=action) 63 | 64 | def default(self, datastring): 65 | return {} 66 | 67 | 68 | class JSONDeserializer(TextDeserializer): 69 | 70 | def _from_json(self, datastring): 71 | try: 72 | return jsonutils.loads(datastring) 73 | except ValueError: 74 | msg = _("Cannot understand JSON") 75 | raise exception.MalformedResponseBody(reason=msg) 76 | 77 | def default(self, datastring): 78 | return {'body': self._from_json(datastring)} 79 | 80 | 81 | # NOTE(maru): this class is duplicated from tacker.wsgi 82 | class Serializer(object): 83 | """Serializes and deserializes dictionaries to certain MIME types.""" 84 | 85 | def __init__(self, metadata=None): 86 | """Create a serializer based on the given WSGI environment. 87 | 88 | 'metadata' is an optional dict mapping MIME types to information 89 | needed to serialize a dictionary to that type. 90 | 91 | """ 92 | self.metadata = metadata or {} 93 | 94 | def _get_serialize_handler(self, content_type): 95 | handlers = { 96 | 'application/json': JSONDictSerializer() 97 | } 98 | 99 | try: 100 | return handlers[content_type] 101 | except Exception: 102 | raise exception.InvalidContentType(content_type=content_type) 103 | 104 | def serialize(self, data, content_type): 105 | """Serialize a dictionary into the specified content type.""" 106 | return self._get_serialize_handler(content_type).serialize(data) 107 | 108 | def deserialize(self, datastring, content_type): 109 | """Deserialize a string to a dictionary. 110 | 111 | The string must be in the format of a supported MIME type. 112 | """ 113 | return self.get_deserialize_handler(content_type).deserialize( 114 | datastring) 115 | 116 | def get_deserialize_handler(self, content_type): 117 | handlers = { 118 | 'application/json': JSONDeserializer() 119 | } 120 | 121 | try: 122 | return handlers[content_type] 123 | except Exception: 124 | raise exception.InvalidContentType(content_type=content_type) 125 | -------------------------------------------------------------------------------- /tackerclient/common/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011, VMware, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | # 15 | # Borrowed from nova code base, more utilities will be added/borrowed as and 16 | # when needed. 17 | 18 | """Utilities and helper functions.""" 19 | 20 | import argparse 21 | import logging 22 | import os 23 | 24 | from oslo_utils import encodeutils 25 | from oslo_utils import importutils 26 | 27 | from tackerclient.common import exceptions 28 | from tackerclient.i18n import _ 29 | 30 | 31 | def env(*vars, **kwargs): 32 | """Returns the first environment variable set. 33 | 34 | If none are non-empty, defaults to '' or keyword arg default. 35 | """ 36 | for v in vars: 37 | value = os.environ.get(v) 38 | if value: 39 | return value 40 | return kwargs.get('default', '') 41 | 42 | 43 | def get_client_class(api_name, version, version_map): 44 | """Returns the client class for the requested API version. 45 | 46 | :param api_name: the name of the API, e.g. 'compute', 'image', etc 47 | :param version: the requested API version 48 | :param version_map: a dict of client classes keyed by version 49 | :rtype: a client class for the requested API version 50 | """ 51 | try: 52 | client_path = version_map[str(version)] 53 | except (KeyError, ValueError): 54 | msg = _("Invalid %(api_name)s client version '%(version)s'. must be " 55 | "one of: %(map_keys)s") 56 | msg = msg % {'api_name': api_name, 'version': version, 57 | 'map_keys': ', '.join(version_map.keys())} 58 | raise exceptions.UnsupportedVersion(message=msg) 59 | 60 | return importutils.import_class(client_path) 61 | 62 | 63 | def get_item_properties(item, fields, mixed_case_fields=(), formatters=None): 64 | """Return a tuple containing the item properties. 65 | 66 | :param item: a single item resource (e.g. Server, Tenant, etc) 67 | :param fields: tuple of strings with the desired field names 68 | :param mixed_case_fields: tuple of field names to preserve case 69 | :param formatters: dictionary mapping field names to callables 70 | to format the values 71 | """ 72 | if formatters is None: 73 | formatters = {} 74 | 75 | row = [] 76 | 77 | for field in fields: 78 | if field in formatters: 79 | row.append(formatters[field](item)) 80 | else: 81 | if field in mixed_case_fields: 82 | field_name = field.replace(' ', '_') 83 | else: 84 | field_name = field.lower().replace(' ', '_') 85 | if not hasattr(item, field_name) and isinstance(item, dict): 86 | data = item[field_name] 87 | else: 88 | data = getattr(item, field_name, '') 89 | if data is None: 90 | data = '' 91 | row.append(data) 92 | return tuple(row) 93 | 94 | 95 | def str2bool(strbool): 96 | if strbool is None: 97 | return None 98 | return strbool.lower() == 'true' 99 | 100 | 101 | def str2dict(strdict): 102 | """Convert key1=value1,key2=value2,... string into dictionary. 103 | 104 | :param strdict: key1=value1,key2=value2 105 | """ 106 | if not strdict: 107 | return {} 108 | return dict([kv.split('=', 1) for kv in strdict.split(',')]) 109 | 110 | 111 | def http_log_req(_logger, args, kwargs): 112 | if not _logger.isEnabledFor(logging.DEBUG): 113 | return 114 | 115 | string_parts = ['curl -i'] 116 | for element in args: 117 | if element in ('GET', 'POST', 'DELETE', 'PUT'): 118 | string_parts.append(' -X %s' % element) 119 | else: 120 | string_parts.append(' %s' % element) 121 | 122 | for element in kwargs['headers']: 123 | header = ' -H "%s: %s"' % (element, kwargs['headers'][element]) 124 | string_parts.append(header) 125 | 126 | if 'body' in kwargs and kwargs['body']: 127 | string_parts.append(" -d '%s'" % (kwargs['body'])) 128 | req = encodeutils.safe_encode("".join(string_parts)) 129 | _logger.debug("\nREQ: %s\n", req) 130 | 131 | 132 | def http_log_resp(_logger, resp, body): 133 | if not _logger.isEnabledFor(logging.DEBUG): 134 | return 135 | _logger.debug("RESP:%(code)s %(headers)s %(body)s\n", 136 | {'code': resp.status_code, 137 | 'headers': resp.headers, 138 | 'body': body}) 139 | 140 | 141 | def _safe_encode_without_obj(data): 142 | if isinstance(data, str): 143 | return encodeutils.safe_encode(data) 144 | return data 145 | 146 | 147 | def safe_encode_list(data): 148 | return list(map(_safe_encode_without_obj, data)) 149 | 150 | 151 | def safe_encode_dict(data): 152 | def _encode_item(item): 153 | k, v = item 154 | if isinstance(v, list): 155 | return (k, safe_encode_list(v)) 156 | elif isinstance(v, dict): 157 | return (k, safe_encode_dict(v)) 158 | return (k, _safe_encode_without_obj(v)) 159 | 160 | return dict(list(map(_encode_item, data.items()))) 161 | 162 | 163 | def add_boolean_argument(parser, name, **kwargs): 164 | for keyword in ('metavar', 'choices'): 165 | kwargs.pop(keyword, None) 166 | default = kwargs.pop('default', argparse.SUPPRESS) 167 | parser.add_argument( 168 | name, 169 | metavar='{True,False}', 170 | choices=['True', 'true', 'False', 'false'], 171 | default=default, 172 | **kwargs) 173 | 174 | 175 | def get_file_path(filename): 176 | file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 177 | '../%s' % filename)) 178 | return file_path 179 | -------------------------------------------------------------------------------- /tackerclient/common/validators.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 NEC Corporation 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import netaddr 17 | 18 | from tackerclient.common import exceptions 19 | from tackerclient.i18n import _ 20 | 21 | 22 | def validate_int_range(parsed_args, attr_name, min_value=None, max_value=None): 23 | val = getattr(parsed_args, attr_name, None) 24 | if val is None: 25 | return 26 | try: 27 | if not isinstance(val, int): 28 | int_val = int(val, 0) 29 | else: 30 | int_val = val 31 | if ((min_value is None or min_value <= int_val) and 32 | (max_value is None or int_val <= max_value)): 33 | return 34 | except (ValueError, TypeError): 35 | pass 36 | 37 | if min_value is not None and max_value is not None: 38 | msg = (_('%(attr_name)s "%(val)s" should be an integer ' 39 | '[%(min)i:%(max)i].') % 40 | {'attr_name': attr_name.replace('_', '-'), 41 | 'val': val, 'min': min_value, 'max': max_value}) 42 | elif min_value is not None: 43 | msg = (_('%(attr_name)s "%(val)s" should be an integer ' 44 | 'greater than or equal to %(min)i.') % 45 | {'attr_name': attr_name.replace('_', '-'), 46 | 'val': val, 'min': min_value}) 47 | elif max_value is not None: 48 | msg = (_('%(attr_name)s "%(val)s" should be an integer ' 49 | 'smaller than or equal to %(max)i.') % 50 | {'attr_name': attr_name.replace('_', '-'), 51 | 'val': val, 'max': max_value}) 52 | else: 53 | msg = (_('%(attr_name)s "%(val)s" should be an integer.') % 54 | {'attr_name': attr_name.replace('_', '-'), 55 | 'val': val}) 56 | 57 | raise exceptions.CommandError(message=msg) 58 | 59 | 60 | def validate_ip_subnet(parsed_args, attr_name): 61 | val = getattr(parsed_args, attr_name) 62 | if not val: 63 | return 64 | try: 65 | netaddr.IPNetwork(val) 66 | except (netaddr.AddrFormatError, ValueError): 67 | raise exceptions.CommandError( 68 | message=(_('%(attr_name)s "%(val)s" is not a valid CIDR.') % 69 | {'attr_name': attr_name.replace('_', '-'), 'val': val})) 70 | -------------------------------------------------------------------------------- /tackerclient/i18n.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import oslo_i18n as i18n 14 | 15 | _translators = i18n.TranslatorFactory(domain='tackerclient') 16 | 17 | # The primary translation function using the well-known name "_" 18 | _ = _translators.primary 19 | -------------------------------------------------------------------------------- /tackerclient/osc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/common/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/common/vnflcm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/common/vnflcm/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/common/vnflcm/vnflcm_versions.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nippon Telegraph and Telephone Corporation 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from osc_lib.command import command 17 | 18 | from tackerclient.common import exceptions 19 | from tackerclient.i18n import _ 20 | 21 | 22 | SUPPORTED_VERSIONS = [1, 2] 23 | 24 | 25 | class VnfLcmVersions(command.ShowOne): 26 | _description = _("Show VnfLcm Api versions") 27 | 28 | def get_parser(self, prog_name): 29 | parser = super(VnfLcmVersions, self).get_parser(prog_name) 30 | parser.add_argument( 31 | '--major-version', 32 | metavar="", 33 | type=int, 34 | help=_('Show only specify major version.')) 35 | return parser 36 | 37 | def take_action(self, parsed_args): 38 | v = None 39 | if parsed_args.major_version: 40 | if parsed_args.major_version not in SUPPORTED_VERSIONS: 41 | msg = _("Major version %d is not supported") 42 | reason = msg % parsed_args.major_version 43 | raise exceptions.InvalidInput(reason=reason) 44 | v = "v{}".format(parsed_args.major_version) 45 | 46 | client = self.app.client_manager.tackerclient 47 | data = client.show_vnf_lcm_versions(v) 48 | 49 | return (tuple(data.keys()), tuple(data.values())) 50 | -------------------------------------------------------------------------------- /tackerclient/osc/plugin.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | # 13 | 14 | """OpenStackClient plugin for nfv-orchestration service.""" 15 | 16 | import logging 17 | 18 | from osc_lib import utils 19 | 20 | 21 | LOG = logging.getLogger(__name__) 22 | 23 | # Required by the OSC plugin interface 24 | DEFAULT_TACKER_API_VERSION = '1' 25 | API_NAME = 'tackerclient' 26 | API_VERSION_OPTION = 'os_tacker_api_version' 27 | API_VERSIONS = { 28 | '1': 'tackerclient.v1_0.client.Client', 29 | '2': 'tackerclient.v1_0.client.Client', 30 | } 31 | 32 | 33 | def make_client(instance): 34 | """Returns a client to the ClientManager.""" 35 | 36 | api_version = instance._api_version[API_NAME] 37 | tacker_client = utils.get_client_class( 38 | API_NAME, 39 | api_version, 40 | API_VERSIONS) 41 | LOG.debug('Instantiating tacker client: %s', tacker_client) 42 | 43 | kwargs = {'service_type': 'nfv-orchestration', 44 | 'region_name': instance._region_name, 45 | 'endpoint_type': instance._interface, 46 | 'interface': instance._interface, 47 | 'session': instance.session, 48 | 'api_version': api_version 49 | } 50 | 51 | client = tacker_client(**kwargs) 52 | 53 | return client 54 | 55 | 56 | def build_option_parser(parser): 57 | """Hook to add global options.""" 58 | parser.add_argument( 59 | '--os-tacker-api-version', 60 | metavar='', 61 | default=utils.env( 62 | 'OS_TACKER_API_VERSION', 63 | default=DEFAULT_TACKER_API_VERSION)) 64 | return parser 65 | -------------------------------------------------------------------------------- /tackerclient/osc/sdk_utils.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import sys 14 | 15 | from oslo_utils import encodeutils 16 | 17 | 18 | def get_osc_show_columns_for_sdk_resource( 19 | sdk_resource, 20 | osc_column_map, 21 | invisible_columns=None 22 | ): 23 | """Get and filter the display and attribute columns for an SDK resource. 24 | 25 | Common utility function for preparing the output of an OSC show command. 26 | Some of the columns may need to get renamed, others made invisible. 27 | 28 | :param sdk_resource: An SDK resource 29 | :param osc_column_map: A hash of mappings for display column names 30 | :param invisible_columns: A list of invisible column names 31 | 32 | :returns: Two tuples containing the names of the display and attribute 33 | columns 34 | """ 35 | 36 | if getattr(sdk_resource, 'allow_get', None) is not None: 37 | resource_dict = sdk_resource.to_dict( 38 | body=True, headers=False, ignore_none=False) 39 | else: 40 | resource_dict = sdk_resource 41 | 42 | # Build the OSC column names to display for the SDK resource. 43 | attr_map = {} 44 | display_columns = list(resource_dict.keys()) 45 | invisible_columns = [] if invisible_columns is None else invisible_columns 46 | for col_name in invisible_columns: 47 | if col_name in display_columns: 48 | display_columns.remove(col_name) 49 | for sdk_attr, osc_attr in osc_column_map.items(): 50 | if sdk_attr in display_columns: 51 | attr_map[osc_attr] = sdk_attr 52 | display_columns.remove(sdk_attr) 53 | if osc_attr not in display_columns: 54 | display_columns.append(osc_attr) 55 | sorted_display_columns = sorted(display_columns) 56 | 57 | # Build the SDK attribute names for the OSC column names. 58 | attr_columns = [] 59 | for column in sorted_display_columns: 60 | new_column = attr_map[column] if column in attr_map else column 61 | attr_columns.append(new_column) 62 | return tuple(sorted_display_columns), tuple(attr_columns) 63 | 64 | 65 | class DictModel(dict): 66 | """Convert dict into an object that provides attribute access to values.""" 67 | 68 | def __init__(self, *args, **kwargs): 69 | """Convert dict values to DictModel values.""" 70 | super(DictModel, self).__init__(*args, **kwargs) 71 | 72 | def needs_upgrade(item): 73 | return isinstance(item, dict) and not isinstance(item, DictModel) 74 | 75 | def upgrade(item): 76 | """Upgrade item if it needs to be upgraded.""" 77 | if needs_upgrade(item): 78 | return DictModel(item) 79 | else: 80 | return item 81 | 82 | for key, value in self.items(): 83 | if isinstance(value, (list, tuple)): 84 | # Keep the same type but convert dicts to DictModels 85 | self[key] = type(value)( 86 | (upgrade(item) for item in value) 87 | ) 88 | elif needs_upgrade(value): 89 | # Change dict instance values to DictModel instance values 90 | self[key] = DictModel(value) 91 | 92 | def __getattr__(self, name): 93 | try: 94 | return self[name] 95 | except KeyError as e: 96 | raise AttributeError(e) 97 | 98 | def __setattr__(self, name, value): 99 | self[name] = value 100 | 101 | def __delattr__(self, name): 102 | del self[name] 103 | 104 | def __str__(self): 105 | pairs = ['%s=%s' % (k, v) for k, v in self.items()] 106 | return ', '.join(sorted(pairs)) 107 | 108 | 109 | def save_data(data, path): 110 | """Save data to the specified path. 111 | 112 | :param data: binary or string data 113 | :param path: file path to save data 114 | """ 115 | if path is None: 116 | vnfpackage = getattr(sys.stdout, 'buffer', sys.stdout) 117 | else: 118 | mode = 'wb' if isinstance(data, bytes) else 'w' 119 | vnfpackage = open(path, mode) 120 | try: 121 | vnfpackage.write(data) 122 | finally: 123 | vnfpackage.close() 124 | 125 | 126 | def exit(msg=None, exit_code=1): 127 | if msg: 128 | print(encodeutils.safe_decode(msg)) 129 | sys.exit(exit_code) 130 | -------------------------------------------------------------------------------- /tackerclient/osc/v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/v1/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/v1/nfvo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/v1/nfvo/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/v1/vnflcm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/v1/vnflcm/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/v1/vnflcm/samples/change_ext_conn_vnf_instance_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "extVirtualLinks": [ 3 | { 4 | "id": "ext-vl-uuid-VL1", 5 | "resourceId": "neutron-network-uuid_VL1", 6 | "extCps": [ 7 | { 8 | "cpdId": "CP1", 9 | "cpConfig": [ 10 | { 11 | "cpProtocolData": [ 12 | { 13 | "layerProtocol": "IP_OVER_ETHERNET", 14 | "ipOverEthernet": { 15 | "ipAddresses": [ 16 | { 17 | "type": "IPV4", 18 | "numDynamicAddresses": 1, 19 | "subnetId": "subnet-uuid" 20 | } 21 | ] 22 | } 23 | } 24 | ] 25 | } 26 | ] 27 | }, 28 | { 29 | "cpdId": "CP2", 30 | "cpConfig": [ 31 | { 32 | "cpProtocolData": [ 33 | { 34 | "layerProtocol": "IP_OVER_ETHERNET", 35 | "ipOverEthernet": { 36 | "ipAddresses": [ 37 | { 38 | "type": "IPV4", 39 | "fixedAddresses": [ 40 | "10.0.0.1" 41 | ], 42 | "subnetId": "subnet-uuid" 43 | } 44 | ] 45 | } 46 | } 47 | ] 48 | } 49 | ] 50 | } 51 | ] 52 | } 53 | ], 54 | "vimConnectionInfo": [ 55 | { 56 | "id": "vim-uuid", 57 | "vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2", 58 | "vimConnectionId": "dummy-vimid", 59 | "interfaceInfo": { 60 | "key1":"value1", 61 | "key2":"value2" 62 | }, 63 | "accessInfo": { 64 | "key1":"value1", 65 | "key2":"value2" 66 | } 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /tackerclient/osc/v1/vnflcm/samples/create_lccn_subscription_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "filter": { 3 | "vnfInstanceSubscriptionFilter": { 4 | "vnfdIds": [ 5 | "dummy-vnfdId-1", 6 | "dummy-vnfdId-2" 7 | ], 8 | "vnfProductsFromProviders": [ 9 | { 10 | "vnfProvider": "dummy-vnfProvider-1", 11 | "vnfProducts": [ 12 | { 13 | "vnfProductName": "dummy-vnfProductName-1-1", 14 | "versions": [ 15 | { 16 | "vnfSoftwareVersion": "1.0", 17 | "vnfdVersions": ["1.0", "2.0"] 18 | }, 19 | { 20 | "vnfSoftwareVersion": "1.1", 21 | "vnfdVersions": ["1.1", "2.1"] 22 | } 23 | ] 24 | }, 25 | { 26 | "vnfProductName": "dummy-vnfProductName-1-2", 27 | "versions": [ 28 | { 29 | "vnfSoftwareVersion": "1.0", 30 | "vnfdVersions": ["1.0", "2.0"] 31 | }, 32 | { 33 | "vnfSoftwareVersion": "1.1", 34 | "vnfdVersions": ["1.1", "2.1"] 35 | } 36 | ] 37 | } 38 | ] 39 | }, 40 | { 41 | "vnfProvider": "dummy-vnfProvider-2", 42 | "vnfProducts": [ 43 | { 44 | "vnfProductName": "dummy-vnfProductName-2-1", 45 | "versions": [ 46 | { 47 | "vnfSoftwareVersion": "1.0", 48 | "vnfdVersions": ["1.0", "2.0"] 49 | }, 50 | { 51 | "vnfSoftwareVersion": "1.1", 52 | "vnfdVersions": ["1.1", "2.1"] 53 | } 54 | ] 55 | }, 56 | { 57 | "vnfProductName": "dummy-vnfProductName-2-2", 58 | "versions": [ 59 | { 60 | "vnfSoftwareVersion": "1.0", 61 | "vnfdVersions": ["1.0", "2.0"] 62 | }, 63 | { 64 | "vnfSoftwareVersion": "1.1", 65 | "vnfdVersions": ["1.1", "2.1"] 66 | } 67 | ] 68 | } 69 | ] 70 | } 71 | ], 72 | "vnfInstanceIds": [ 73 | "dummy-vnfInstanceId-1", 74 | "dummy-vnfInstanceId-2" 75 | ], 76 | "vnfInstanceNames": [ 77 | "dummy-vnfInstanceName-1", 78 | "dummy-vnfInstanceName-2" 79 | ] 80 | }, 81 | "notificationTypes": [ 82 | "VnfLcmOperationOccurrenceNotification", 83 | "VnfIdentifierCreationNotification", 84 | "VnfIdentifierDeletionNotification" 85 | ], 86 | "operationTypes": [ 87 | "INSTANTIATE", 88 | "SCALE", 89 | "TERMINATE", 90 | "HEAL", 91 | "MODIFY_INFO", 92 | "CHANGE_EXT_CONN" 93 | ], 94 | "operationStates": [ 95 | "COMPLETED", 96 | "FAILED", 97 | "FAILED_TEMP", 98 | "PROCESSING", 99 | "ROLLING_BACK", 100 | "ROLLED_BACK", 101 | "STARTING" 102 | ] 103 | }, 104 | "callbackUri": "http://localhost:9990/notification/callback/test", 105 | "authentication": { 106 | "authType": [ 107 | "BASIC" 108 | ], 109 | "paramsBasic": { 110 | "password": "test_pass", 111 | "userName": "test_user" 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /tackerclient/osc/v1/vnflcm/samples/heal_vnf_instance_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "additionalParams": {"all": true} 3 | } 4 | -------------------------------------------------------------------------------- /tackerclient/osc/v1/vnflcm/samples/instantiate_vnf_instance_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "flavourId":"simple", 3 | "instantiationLevelId":"instantiation_level_1", 4 | "extVirtualLinks":[ 5 | { 6 | "id":"ext-vl-uuid-VL1", 7 | "vimConnectionId":"vim-uuid", 8 | "resourceProviderId":"resource-provider-id", 9 | "resourceId":"neutron-network-uuid_VL1", 10 | "extCps":[ 11 | { 12 | "cpdId":"CP1", 13 | "cpConfig":[ 14 | { 15 | "cpInstanceId":"cp-instance-id", 16 | "linkPortId":"link-port-uuid_CP1", 17 | "cpProtocolData":[ 18 | { 19 | "layerProtocol":"IP_OVER_ETHERNET", 20 | "ipOverEthernet":{ 21 | "macAddress":"00:25:96:FF:FE:12:34:56", 22 | "ipAddresses":[ 23 | { 24 | "addressRange":{ 25 | "minAddress":"192.168.11.01", 26 | "maxAddress":"192.168.21.201" 27 | }, 28 | "subnetId":"neutron-subnet-uuid_CP1" 29 | } 30 | ] 31 | } 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | ], 38 | "extLinkPorts":[ 39 | { 40 | "id":"link-port-uuid_CP1", 41 | "resourceHandle":{ 42 | "vimConnectionId":"vim-uuid", 43 | "resourceProviderId":"resource-provider-id", 44 | "resourceId":"neutron-port-uuid_CP1", 45 | "vimLevelResourceType":"LINKPORT" 46 | } 47 | } 48 | ] 49 | } 50 | ], 51 | "extManagedVirtualLinks":[ 52 | { 53 | "id":"extMngVLnk-uuid_VL3", 54 | "vnfVirtualLinkDescId":"VL3", 55 | "vimConnectionId":"vim-uuid", 56 | "resourceProviderId":"resource-provider-id", 57 | "resourceId":"neutron-network-uuid_VL3" 58 | } 59 | ], 60 | "vimConnectionInfo":[ 61 | { 62 | "id":"vim-uuid", 63 | "vimId":"dummy-vimid", 64 | "vimType":"ETSINFV.OPENSTACK_KEYSTONE.v_2", 65 | "interfaceInfo":{ 66 | "key1":"value1", 67 | "key2":"value2" 68 | }, 69 | "accessInfo":{ 70 | "key1":"value1", 71 | "key2":"value2" 72 | }, 73 | "extra":{ 74 | "key1":"value1", 75 | "key2":"value2" 76 | } 77 | } 78 | ] 79 | } -------------------------------------------------------------------------------- /tackerclient/osc/v1/vnflcm/samples/scale_vnf_instance_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "additionalParams": {"key1":"value1", "key2":"value2"} 3 | } -------------------------------------------------------------------------------- /tackerclient/osc/v1/vnflcm/samples/update_vnf_instance_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "vnfInstanceName": "sample", 3 | "vnfInstanceDescription" : "sample_description", 4 | "vnfdId" : "sample_id" 5 | } -------------------------------------------------------------------------------- /tackerclient/osc/v1/vnfpkgm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/v1/vnfpkgm/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/v2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/v2/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnffm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/v2/vnffm/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnffm/samples/create_vnf_fm_subscription_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "filter": { 3 | "vnfInstanceSubscriptionFilter": { 4 | "vnfdIds": [ 5 | "dummy-vnfdId-1" 6 | ], 7 | "vnfProductsFromProviders": [ 8 | { 9 | "vnfProvider": "dummy-vnfProvider-1", 10 | "vnfProducts": [ 11 | { 12 | "vnfProductName": "dummy-vnfProductName-1-1", 13 | "versions": [ 14 | { 15 | "vnfSoftwareVersion": 1.0, 16 | "vnfdVersions": [1.0, 2.0] 17 | } 18 | ] 19 | } 20 | ] 21 | } 22 | ], 23 | "vnfInstanceIds": [ 24 | "dummy-vnfInstanceId-1" 25 | ], 26 | "vnfInstanceNames": [ 27 | "dummy-vnfInstanceName-1" 28 | ] 29 | }, 30 | "notificationTypes": [ 31 | "AlarmNotification" 32 | ], 33 | "faultyResourceTypes": [ 34 | "COMPUTE" 35 | ], 36 | "perceivedSeverities": [ 37 | "WARNING" 38 | ], 39 | "eventTypes": [ 40 | "EQUIPMENT_ALARM" 41 | ], 42 | "probableCauses": [ 43 | "The server cannot be connected." 44 | ] 45 | }, 46 | "callbackUri": "/nfvo/notify/alarm", 47 | "authentication": { 48 | "authType": [ 49 | "BASIC", 50 | "OAUTH2_CLIENT_CREDENTIALS" 51 | ], 52 | "paramsBasic": { 53 | "userName": "nfvo", 54 | "password": "nfvopwd" 55 | }, 56 | "paramsOauth2ClientCredentials": { 57 | "clientId": "auth_user_name", 58 | "clientPassword": "auth_password", 59 | "tokenEndpoint": "token_endpoint" 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnffm/vnffm_sub.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Fujitsu 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import logging 17 | 18 | from osc_lib.command import command 19 | from osc_lib import utils 20 | 21 | from tackerclient.common import exceptions 22 | from tackerclient.i18n import _ 23 | from tackerclient.osc import sdk_utils 24 | from tackerclient.osc import utils as tacker_osc_utils 25 | 26 | LOG = logging.getLogger(__name__) 27 | 28 | _ATTR_MAP = ( 29 | ('id', 'ID', tacker_osc_utils.LIST_BOTH), 30 | ('callbackUri', 'Callback Uri', tacker_osc_utils.LIST_BOTH) 31 | ) 32 | 33 | _FORMATTERS = { 34 | 'filter': tacker_osc_utils.FormatComplexDataColumn, 35 | '_links': tacker_osc_utils.FormatComplexDataColumn 36 | } 37 | 38 | _MIXED_CASE_FIELDS = ( 39 | 'callbackUri' 40 | ) 41 | 42 | _VNF_FM_SUB_ID = 'vnf_fm_sub_id' 43 | 44 | 45 | def _get_columns(vnffm_sub_obj): 46 | column_map = { 47 | 'id': 'ID', 48 | 'filter': 'Filter', 49 | 'callbackUri': 'Callback Uri', 50 | '_links': 'Links' 51 | } 52 | 53 | return sdk_utils.get_osc_show_columns_for_sdk_resource( 54 | vnffm_sub_obj, column_map) 55 | 56 | 57 | class CreateVnfFmSub(command.ShowOne): 58 | _description = _("Create a new VNF FM subscription") 59 | 60 | def get_parser(self, prog_name): 61 | parser = super(CreateVnfFmSub, self).get_parser(prog_name) 62 | parser.add_argument( 63 | 'request_file', 64 | metavar="", 65 | help=_('Specify create VNF FM subscription request ' 66 | 'parameters in a json file.')) 67 | return parser 68 | 69 | def take_action(self, parsed_args): 70 | client = self.app.client_manager.tackerclient 71 | vnf_fm_sub = client.create_vnf_fm_sub( 72 | tacker_osc_utils.jsonfile2body(parsed_args.request_file)) 73 | display_columns, columns = _get_columns(vnf_fm_sub) 74 | data = utils.get_item_properties( 75 | sdk_utils.DictModel(vnf_fm_sub), columns, 76 | formatters=_FORMATTERS, mixed_case_fields=_MIXED_CASE_FIELDS) 77 | return (display_columns, data) 78 | 79 | 80 | class ListVnfFmSub(command.Lister): 81 | _description = _("List VNF FM subs") 82 | 83 | def get_parser(self, prog_name): 84 | LOG.debug('get_parser(%s)', prog_name) 85 | parser = super(ListVnfFmSub, self).get_parser(prog_name) 86 | parser.add_argument( 87 | "--filter", 88 | metavar="", 89 | help=_("Attribute-based-filtering parameters"), 90 | ) 91 | return parser 92 | 93 | def take_action(self, parsed_args): 94 | _params = {} 95 | if parsed_args.filter: 96 | _params['filter'] = parsed_args.filter 97 | 98 | client = self.app.client_manager.tackerclient 99 | data = client.list_vnf_fm_subs(**_params) 100 | headers, columns = tacker_osc_utils.get_column_definitions( 101 | _ATTR_MAP, long_listing=True) 102 | return (headers, 103 | (utils.get_dict_properties( 104 | s, columns, formatters=_FORMATTERS, 105 | mixed_case_fields=_MIXED_CASE_FIELDS, 106 | ) for s in data['vnf_fm_subs'])) 107 | 108 | 109 | class ShowVnfFmSub(command.ShowOne): 110 | _description = _("Display VNF FM subscription details") 111 | 112 | def get_parser(self, prog_name): 113 | parser = super(ShowVnfFmSub, self).get_parser(prog_name) 114 | parser.add_argument( 115 | _VNF_FM_SUB_ID, 116 | metavar="", 117 | help=_("VNF FM subscription ID to display")) 118 | return parser 119 | 120 | def take_action(self, parsed_args): 121 | client = self.app.client_manager.tackerclient 122 | obj = client.show_vnf_fm_sub(parsed_args.vnf_fm_sub_id) 123 | display_columns, columns = _get_columns(obj) 124 | data = utils.get_item_properties( 125 | sdk_utils.DictModel(obj), columns, 126 | mixed_case_fields=_MIXED_CASE_FIELDS, 127 | formatters=_FORMATTERS) 128 | return (display_columns, data) 129 | 130 | 131 | class DeleteVnfFmSub(command.Command): 132 | _description = _("Delete VNF FM subscription(s)") 133 | 134 | def get_parser(self, prog_name): 135 | parser = super(DeleteVnfFmSub, self).get_parser(prog_name) 136 | parser.add_argument( 137 | _VNF_FM_SUB_ID, 138 | metavar="", 139 | nargs="+", 140 | help=_("VNF FM subscription ID(s) to delete")) 141 | return parser 142 | 143 | def take_action(self, parsed_args): 144 | error_count = 0 145 | client = self.app.client_manager.tackerclient 146 | vnf_fm_sub_ids = parsed_args.vnf_fm_sub_id 147 | 148 | for sub_id in vnf_fm_sub_ids: 149 | try: 150 | client.delete_vnf_fm_sub(sub_id) 151 | except Exception as e: 152 | error_count += 1 153 | LOG.error(_("Failed to delete VNF FM subscription with " 154 | "ID '%(sub_id)s': %(e)s"), 155 | {'sub_id': sub_id, 'e': e}) 156 | 157 | total = len(vnf_fm_sub_ids) 158 | if error_count > 0: 159 | msg = (_("Failed to delete %(error_count)s of %(total)s " 160 | "VNF FM subscriptions.") % {'error_count': error_count, 161 | 'total': total}) 162 | raise exceptions.CommandError(message=msg) 163 | 164 | if total > 1: 165 | print(_('All specified VNF FM subscriptions are deleted ' 166 | 'successfully')) 167 | else: 168 | print(_("VNF FM subscription '%s' deleted " 169 | "successfully") % vnf_fm_sub_ids[0]) 170 | -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnflcm/samples/change_vnfpkg_vnf_instance_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "vnfdId": "c6595341-a5bb-8246-53c4-7aeb843d60c5", 3 | "additionalParams": { 4 | "upgrade_type": "RollingUpdate", 5 | "lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_old_vnf.py", 6 | "lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf", 7 | "lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_new_vnf.py", 8 | "lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf", 9 | "vdu_params": [{ 10 | "vduId": "VDU1", 11 | "old_vnfc_param": { 12 | "cp_name": "VDU1_CP1", 13 | "username": "ubuntu", 14 | "password": "ubuntu" 15 | }, 16 | "new_vnfc_param": { 17 | "cp_name": "VDU1_CP1", 18 | "username": "ubuntu", 19 | "password": "ubuntu" 20 | } 21 | }, { 22 | "vduId": "VDU2", 23 | "old_vnfc_param": { 24 | "cp_name": "VDU2_CP1", 25 | "username": "ubuntu", 26 | "password": "ubuntu" 27 | }, 28 | "new_vnfc_param": { 29 | "cp_name": "VDU2_CP1", 30 | "username": "ubuntu", 31 | "password": "ubuntu" 32 | } 33 | }] 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnfpm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/osc/v2/vnfpm/__init__.py -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnfpm/samples/create_vnf_pm_job_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "objectType": "VNFC", 3 | "objectInstanceIds": [ 4 | "object-instance-id-1" 5 | ], 6 | "subObjectInstanceIds": [ 7 | "sub-object-instance-id-2" 8 | ], 9 | "criteria": { 10 | "performanceMetric": [ 11 | "VCpuUsageMeanVnf.object-instance-id-1" 12 | ], 13 | "performanceMetricGroup": [ 14 | "VirtualisedComputeResource" 15 | ], 16 | "collectionPeriod": "500", 17 | "reportingPeriod": "1000", 18 | "reportingBoundary": "2022/07/25 10:43:55" 19 | }, 20 | "callbackUri": "/nfvo/notify/job", 21 | "authentication": { 22 | "authType": [ 23 | "BASIC", 24 | "OAUTH2_CLIENT_CREDENTIALS" 25 | ], 26 | "paramsBasic": { 27 | "userName": "nfvo", 28 | "password": "nfvopwd" 29 | }, 30 | "paramsOauth2ClientCredentials": { 31 | "clientId": "auth_user_name", 32 | "clientPassword": "auth_password", 33 | "tokenEndpoint": "token_endpoint" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnfpm/samples/create_vnf_pm_threshold_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "objectType": "Vnfc", 3 | "objectInstanceId": "object-instance-id-1", 4 | "subObjectInstanceIds": [ 5 | "sub-object-instance-id-2" 6 | ], 7 | "criteria": { 8 | "performanceMetric": "VCpuUsageMeanVnf.object-instance-id-1", 9 | "thresholdType": "SIMPLE", 10 | "simpleThresholdDetails": { 11 | "thresholdValue": 400.5, 12 | "hysteresis": 10.3 13 | } 14 | }, 15 | "callbackUri": "/nfvo/notify/threshold", 16 | "authentication": { 17 | "authType": [ 18 | "BASIC", 19 | "OAUTH2_CLIENT_CREDENTIALS", 20 | "OAUTH2_CLIENT_CERT" 21 | ], 22 | "paramsBasic": { 23 | "userName": "nfvo", 24 | "password": "nfvopwd" 25 | }, 26 | "paramsOauth2ClientCredentials": { 27 | "clientId": "auth_user_name", 28 | "clientPassword": "auth_password", 29 | "tokenEndpoint": "token_endpoint" 30 | }, 31 | "paramsOauth2ClientCert": { 32 | "clientId": "test", 33 | "certificateRef": { 34 | "type": "x5t#256", 35 | "value": "03c6e188d1fe5d3da8c9bc9a8dc531a2b3e" 36 | }, 37 | "tokenEndpoint": "http://127.0.0.1/token" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnfpm/samples/update_vnf_pm_job_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "callbackUri": "/nfvo/notify/job", 3 | "authentication": { 4 | "authType": [ 5 | "BASIC", 6 | "OAUTH2_CLIENT_CREDENTIALS" 7 | ], 8 | "paramsBasic": { 9 | "userName": "nfvo", 10 | "password": "nfvopwd" 11 | }, 12 | "paramsOauth2ClientCredentials": { 13 | "clientId": "auth_user_name", 14 | "clientPassword": "auth_password", 15 | "tokenEndpoint": "token_endpoint" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnfpm/samples/update_vnf_pm_threshold_param_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "callbackUri": "/nfvo/notify/threshold", 3 | "authentication": { 4 | "authType": [ 5 | "BASIC", 6 | "OAUTH2_CLIENT_CREDENTIALS", 7 | "OAUTH2_CLIENT_CERT" 8 | ], 9 | "paramsBasic": { 10 | "userName": "nfvo", 11 | "password": "nfvopwd" 12 | }, 13 | "paramsOauth2ClientCredentials": { 14 | "clientId": "auth_user_name", 15 | "clientPassword": "auth_password", 16 | "tokenEndpoint": "token_endpoint" 17 | }, 18 | "paramsOauth2ClientCert": { 19 | "clientId": "test", 20 | "certificateRef": { 21 | "type": "x5t#256", 22 | "value": "03c6e188d1fe5d3da8c9bc9a8dc531a2b3e" 23 | }, 24 | "tokenEndpoint": "http://127.0.0.1/token" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tackerclient/osc/v2/vnfpm/vnfpm_report.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Fujitsu 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import logging 17 | 18 | from osc_lib.command import command 19 | from osc_lib import utils 20 | 21 | from tackerclient.i18n import _ 22 | from tackerclient.osc import sdk_utils 23 | from tackerclient.osc import utils as tacker_osc_utils 24 | 25 | LOG = logging.getLogger(__name__) 26 | 27 | _FORMATTERS = { 28 | 'entries': tacker_osc_utils.FormatComplexDataColumn 29 | } 30 | 31 | _VNF_PM_JOB_ID = 'vnf_pm_job_id' 32 | _VNF_PM_REPORT_ID = 'vnf_pm_report_id' 33 | 34 | 35 | def _get_columns(vnfpm_report_obj): 36 | column_map = { 37 | 'entries': 'Entries' 38 | } 39 | return sdk_utils.get_osc_show_columns_for_sdk_resource( 40 | vnfpm_report_obj, column_map) 41 | 42 | 43 | class ShowVnfPmReport(command.ShowOne): 44 | _description = _("Display VNF PM report details") 45 | 46 | def get_parser(self, prog_name): 47 | parser = super(ShowVnfPmReport, self).get_parser(prog_name) 48 | parser.add_argument( 49 | _VNF_PM_JOB_ID, 50 | metavar="", 51 | help=_("VNF PM job id where the VNF PM report is located")) 52 | parser.add_argument( 53 | _VNF_PM_REPORT_ID, 54 | metavar="", 55 | help=_("VNF PM report ID to display")) 56 | return parser 57 | 58 | def take_action(self, parsed_args): 59 | client = self.app.client_manager.tackerclient 60 | obj = client.show_vnf_pm_report( 61 | parsed_args.vnf_pm_job_id, parsed_args.vnf_pm_report_id) 62 | display_columns, columns = _get_columns(obj) 63 | data = utils.get_item_properties( 64 | sdk_utils.DictModel(obj), 65 | columns, formatters=_FORMATTERS, 66 | mixed_case_fields=None) 67 | return (display_columns, data) 68 | -------------------------------------------------------------------------------- /tackerclient/tacker/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tacker/__init__.py -------------------------------------------------------------------------------- /tackerclient/tacker/client.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 OpenStack Foundation. 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | # 16 | 17 | from tackerclient.common._i18n import _ 18 | from tackerclient.common import exceptions 19 | from tackerclient.common import utils 20 | 21 | 22 | API_NAME = 'nfv-orchestration' 23 | API_VERSIONS = { 24 | '1.0': 'tackerclient.v1_0.client.Client', 25 | } 26 | 27 | 28 | def make_client(instance): 29 | """Returns an tacker client.""" 30 | 31 | tacker_client = utils.get_client_class( 32 | API_NAME, 33 | instance._api_version[API_NAME], 34 | API_VERSIONS, 35 | ) 36 | instance.initialize() 37 | url = instance._url 38 | url = url.rstrip("/") 39 | if '1.0' == instance._api_version[API_NAME]: 40 | client = tacker_client(username=instance._username, 41 | tenant_name=instance._tenant_name, 42 | password=instance._password, 43 | region_name=instance._region_name, 44 | auth_url=instance._auth_url, 45 | endpoint_url=url, 46 | endpoint_type=instance._endpoint_type, 47 | token=instance._token, 48 | auth_strategy=instance._auth_strategy, 49 | insecure=instance._insecure, 50 | ca_cert=instance._ca_cert, 51 | retries=instance._retries, 52 | raise_errors=instance._raise_errors, 53 | session=instance._session, 54 | auth=instance._auth) 55 | return client 56 | else: 57 | raise exceptions.UnsupportedVersion( 58 | reason=_("API version %s is not supported") % 59 | instance._api_version[API_NAME]) 60 | 61 | 62 | def Client(api_version, *args, **kwargs): 63 | """Return an tacker client. 64 | 65 | :param api_version: only 1.0 is supported now 66 | """ 67 | tacker_client = utils.get_client_class( 68 | API_NAME, 69 | api_version, 70 | API_VERSIONS, 71 | ) 72 | return tacker_client(*args, **kwargs) 73 | -------------------------------------------------------------------------------- /tackerclient/tacker/v1_0/nfvo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tacker/v1_0/nfvo/__init__.py -------------------------------------------------------------------------------- /tackerclient/tacker/v1_0/nfvo/vim.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Brocade Communications Systems Inc 2 | # All Rights Reserved. 3 | # 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | import yaml 18 | 19 | from oslo_utils import strutils 20 | 21 | from tackerclient.common import exceptions 22 | from tackerclient.i18n import _ 23 | from tackerclient.tacker import v1_0 as tackerV10 24 | from tackerclient.tacker.v1_0.nfvo import vim_utils 25 | 26 | _VIM = "vim" 27 | 28 | 29 | class ListVIM(tackerV10.ListCommand): 30 | """List VIMs that belong to a given tenant.""" 31 | 32 | resource = _VIM 33 | list_columns = ['id', 'tenant_id', 'name', 'type', 'is_default', 34 | 'placement_attr', 'status'] 35 | 36 | 37 | class ShowVIM(tackerV10.ShowCommand): 38 | """Show information of a given VIM.""" 39 | 40 | resource = _VIM 41 | 42 | 43 | class CreateVIM(tackerV10.CreateCommand): 44 | """Create a VIM.""" 45 | 46 | resource = _VIM 47 | 48 | def add_known_arguments(self, parser): 49 | parser.add_argument( 50 | '--config-file', 51 | required=True, 52 | help=_('YAML file with VIM configuration parameters')) 53 | parser.add_argument( 54 | 'name', metavar='NAME', 55 | help=_('Set a name for the VIM')) 56 | parser.add_argument( 57 | '--description', 58 | help=_('Set a description for the VIM')) 59 | parser.add_argument( 60 | '--is-default', 61 | action='store_true', 62 | default=False, 63 | help=_('Set as default VIM')) 64 | 65 | def args2body(self, parsed_args): 66 | body = {self.resource: {}} 67 | if parsed_args.config_file: 68 | with open(parsed_args.config_file) as f: 69 | vim_config = f.read() 70 | try: 71 | config_param = yaml.load(vim_config, 72 | Loader=yaml.SafeLoader) 73 | except yaml.YAMLError as e: 74 | raise exceptions.InvalidInput(reason=e) 75 | vim_obj = body[self.resource] 76 | try: 77 | auth_url = config_param.pop('auth_url') 78 | except KeyError: 79 | raise exceptions.TackerClientException(message='Auth URL must be ' 80 | 'specified', 81 | status_code=404) 82 | vim_obj['auth_url'] = vim_utils.validate_auth_url(auth_url).geturl() 83 | vim_utils.args2body_vim(config_param, vim_obj) 84 | tackerV10.update_dict(parsed_args, body[self.resource], 85 | ['tenant_id', 'name', 'description', 86 | 'is_default']) 87 | return body 88 | 89 | 90 | class UpdateVIM(tackerV10.UpdateCommand): 91 | """Update a given VIM.""" 92 | 93 | resource = _VIM 94 | 95 | def add_known_arguments(self, parser): 96 | parser.add_argument( 97 | '--config-file', 98 | required=False, 99 | help=_('YAML file with VIM configuration parameters')) 100 | parser.add_argument( 101 | '--name', 102 | help=_('New name for the VIM')) 103 | parser.add_argument( 104 | '--description', 105 | help=_('New description for the VIM')) 106 | parser.add_argument( 107 | '--is-default', 108 | type=strutils.bool_from_string, 109 | metavar='{True,False}', 110 | help=_('Indicate whether the VIM is used as default')) 111 | 112 | def args2body(self, parsed_args): 113 | body = {self.resource: {}} 114 | config_param = None 115 | # config arg passed as data overrides config yaml when both args passed 116 | if parsed_args.config_file: 117 | with open(parsed_args.config_file) as f: 118 | config_yaml = f.read() 119 | try: 120 | config_param = yaml.load(config_yaml, 121 | Loader=yaml.SafeLoader) 122 | except yaml.YAMLError as e: 123 | raise exceptions.InvalidInput(reason=e) 124 | vim_obj = body[self.resource] 125 | if config_param is not None: 126 | vim_utils.args2body_vim(config_param, vim_obj) 127 | tackerV10.update_dict(parsed_args, body[self.resource], 128 | ['tenant_id', 'name', 'description', 129 | 'is_default']) 130 | # type attribute is read-only, it can't be updated, so remove it 131 | # in update method 132 | body['vim'].pop('type', None) 133 | return body 134 | 135 | 136 | class DeleteVIM(tackerV10.DeleteCommand): 137 | """Delete given VIM(s).""" 138 | resource = _VIM 139 | -------------------------------------------------------------------------------- /tackerclient/tacker/v1_0/nfvo/vim_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Brocade Communications Systems Inc 2 | # All Rights Reserved. 3 | # 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | from urllib import parse as urlparse 18 | 19 | from tackerclient.common import exceptions 20 | 21 | 22 | def args2body_vim(config_param, vim): 23 | """Create additional args to vim body 24 | 25 | :param vim: vim request object 26 | :return: vim body with args populated 27 | """ 28 | vim_type = ['openstack', 'kubernetes'] 29 | cert_verify_type = ['True', 'False'] 30 | 31 | if 'type' in config_param: 32 | vim['type'] = config_param.pop('type', '') 33 | if not vim['type'] in vim_type: 34 | raise exceptions.TackerClientException( 35 | message='Supported VIM types: openstack, kubernetes', 36 | status_code=400) 37 | else: 38 | vim['type'] = 'openstack' 39 | if vim['type'] == 'openstack': 40 | vim['vim_project'] = { 41 | 'name': config_param.pop('project_name', ''), 42 | 'project_domain_name': 43 | config_param.pop('project_domain_name', '')} 44 | if not vim['vim_project']['name']: 45 | raise exceptions.TackerClientException( 46 | message='Project name must be specified', 47 | status_code=404) 48 | cert_verify = config_param.pop('cert_verify', 'True') 49 | if cert_verify not in cert_verify_type: 50 | raise exceptions.TackerClientException( 51 | message='Supported cert_verify types: True, False', 52 | status_code=400) 53 | vim['auth_cred'] = {'username': config_param.pop('username', ''), 54 | 'password': config_param.pop('password', ''), 55 | 'user_domain_name': 56 | config_param.pop('user_domain_name', ''), 57 | 'cert_verify': cert_verify} 58 | elif vim['type'] == 'kubernetes': 59 | vim['vim_project'] = { 60 | 'name': config_param.pop('project_name', '')} 61 | if not vim['vim_project']['name']: 62 | raise exceptions.TackerClientException( 63 | message='Project name must be specified in Kubernetes VIM,' 64 | 'it is namespace in Kubernetes environment', 65 | status_code=404) 66 | if 'oidc_token_url' in config_param: 67 | if ('username' not in config_param or 68 | 'password' not in config_param or 69 | 'client_id' not in config_param): 70 | # the username, password, client_id are required. 71 | # client_secret is not required when client type is public. 72 | raise exceptions.TackerClientException( 73 | message='oidc_token_url must be specified with username,' 74 | ' password, client_id, client_secret(optional).', 75 | status_code=404) 76 | vim['auth_cred'] = { 77 | 'oidc_token_url': config_param.pop('oidc_token_url'), 78 | 'username': config_param.pop('username'), 79 | 'password': config_param.pop('password'), 80 | 'client_id': config_param.pop('client_id')} 81 | if 'client_secret' in config_param: 82 | vim['auth_cred']['client_secret'] = config_param.pop( 83 | 'client_secret') 84 | elif ('username' in config_param) and ('password' in config_param): 85 | vim['auth_cred'] = { 86 | 'username': config_param.pop('username', ''), 87 | 'password': config_param.pop('password', '')} 88 | elif 'bearer_token' in config_param: 89 | vim['auth_cred'] = { 90 | 'bearer_token': config_param.pop('bearer_token', '')} 91 | else: 92 | raise exceptions.TackerClientException( 93 | message='username and password or bearer_token must be' 94 | 'provided', 95 | status_code=404) 96 | ssl_ca_cert = config_param.pop('ssl_ca_cert', '') 97 | if ssl_ca_cert: 98 | vim['auth_cred']['ssl_ca_cert'] = ssl_ca_cert 99 | if 'extra' in config_param: 100 | vim['extra'] = config_param.pop('extra') 101 | 102 | 103 | def validate_auth_url(url): 104 | url_parts = urlparse.urlparse(url) 105 | if not url_parts.scheme or not url_parts.netloc: 106 | raise exceptions.TackerClientException(message='Invalid auth URL') 107 | return url_parts 108 | -------------------------------------------------------------------------------- /tackerclient/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tests/__init__.py -------------------------------------------------------------------------------- /tackerclient/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tests/unit/__init__.py -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tests/unit/osc/__init__.py -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/base.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 NTT DATA 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from requests_mock.contrib import fixture as requests_mock_fixture 17 | import testtools 18 | from unittest import mock 19 | 20 | from cliff import columns as cliff_columns 21 | 22 | 23 | class FixturedTestCase(testtools.TestCase): 24 | client_fixture_class = None 25 | api_version = '1' 26 | 27 | def setUp(self): 28 | super(FixturedTestCase, self).setUp() 29 | self.app = mock.MagicMock() 30 | if self.client_fixture_class: 31 | self.requests_mock = self.useFixture(requests_mock_fixture. 32 | Fixture()) 33 | fix = self.client_fixture_class(self.requests_mock, 34 | api_version=self.api_version) 35 | self.cs = self.useFixture(fix).client 36 | 37 | def check_parser(self, cmd, args, verify_args): 38 | cmd_parser = cmd.get_parser('check_parser') 39 | try: 40 | parsed_args = cmd_parser.parse_args(args) 41 | except SystemExit: 42 | raise ParserException 43 | for av in verify_args: 44 | attr, value = av 45 | if attr: 46 | self.assertIn(attr, parsed_args) 47 | self.assertEqual(getattr(parsed_args, attr), value) 48 | return parsed_args 49 | 50 | def assertNotCalled(self, m, msg=None): 51 | """Assert a function was not called""" 52 | 53 | if m.called: 54 | if not msg: 55 | msg = 'method %s should not have been called' % m 56 | self.fail(msg) 57 | 58 | def assertListItemsEqual(self, expected, actual): 59 | """Assertion based on human_readable values of list items""" 60 | 61 | self.assertEqual(len(expected), len(actual)) 62 | for col_expected, col_actual in zip(expected, actual): 63 | if isinstance(col_actual, tuple): 64 | self.assertListItemsEqual(col_expected, col_actual) 65 | elif isinstance(col_expected, cliff_columns.FormattableColumn): 66 | self.assertIsInstance(col_actual, col_expected.__class__) 67 | self.assertEqual(col_expected.human_readable(), 68 | col_actual.human_readable()) 69 | else: 70 | self.assertEqual(col_expected, col_actual) 71 | 72 | 73 | class ParserException(Exception): 74 | pass 75 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tests/unit/osc/common/__init__.py -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/common/test_vnflcm_versions.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nippon Telegraph and Telephone Corporation 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import os 17 | 18 | import ddt 19 | from unittest import mock 20 | 21 | from tackerclient.common import exceptions 22 | from tackerclient.osc.common.vnflcm import vnflcm_versions 23 | from tackerclient.tests.unit.osc import base 24 | from tackerclient.tests.unit.osc.v1.fixture_data import client 25 | 26 | 27 | class TestVnfLcm(base.FixturedTestCase): 28 | client_fixture_class = client.ClientFixture 29 | 30 | def setUp(self): 31 | super(TestVnfLcm, self).setUp() 32 | self.url = client.TACKER_URL 33 | self.header = {'content-type': 'application/json'} 34 | self.app = mock.Mock() 35 | self.app_args = mock.Mock() 36 | self.client_manager = self.cs 37 | self.app.client_manager.tackerclient = self.client_manager 38 | 39 | 40 | @ddt.ddt 41 | class TestVnfLcmVersions(TestVnfLcm): 42 | 43 | def setUp(self): 44 | super(TestVnfLcmVersions, self).setUp() 45 | self.vnflcm_versions = vnflcm_versions.VnfLcmVersions( 46 | self.app, self.app_args, cmd_name='vnflcm versions') 47 | 48 | def _versions_response(self, major_version=None): 49 | if major_version is None: 50 | return {"uriPrefix": "/vnflcm", 51 | "apiVersions": [{"version": "1.3.0", 52 | "isDeprecated": False}, 53 | {"version": "2.0.0", 54 | "isDeprecated": False}]} 55 | elif major_version == "1": 56 | return {"uriPrefix": "/vnflcm/v1", 57 | "apiVersions": [{"version": "1.3.0", 58 | "isDeprecated": False}]} 59 | elif major_version == "2": 60 | return {"uriPrefix": "/vnflcm/v2", 61 | "apiVersions": [{"version": "2.0.0", 62 | "isDeprecated": False}]} 63 | 64 | def test_invalid_major_version(self): 65 | parser = self.vnflcm_versions.get_parser('vnflcm versions') 66 | parsed_args = parser.parse_args(["--major-version", "3"]) 67 | self.assertRaises(exceptions.InvalidInput, 68 | self.vnflcm_versions.take_action, 69 | parsed_args) 70 | 71 | def test_take_action_no_arg(self): 72 | parser = self.vnflcm_versions.get_parser('vnflcm versions') 73 | parsed_args = parser.parse_args([]) 74 | 75 | response = self._versions_response() 76 | self.requests_mock.register_uri( 77 | 'GET', os.path.join(self.url, 'vnflcm/api_versions'), 78 | json=response, headers=self.header) 79 | 80 | colmns, data = self.vnflcm_versions.take_action(parsed_args) 81 | 82 | self.assertEqual(colmns, tuple(response.keys())) 83 | self.assertEqual(data, tuple(response.values())) 84 | 85 | @ddt.data('1', '2') 86 | def test_take_action_with_major_version(self, major_version): 87 | parser = self.vnflcm_versions.get_parser('vnflcm versions') 88 | parsed_args = parser.parse_args(["--major-version", 89 | major_version]) 90 | 91 | response = self._versions_response(major_version) 92 | self.requests_mock.register_uri( 93 | 'GET', 94 | os.path.join(self.url, 95 | 'vnflcm/v{}/api_versions'.format(major_version)), 96 | json=response, headers=self.header) 97 | 98 | colmns, data = self.vnflcm_versions.take_action(parsed_args) 99 | 100 | self.assertEqual(colmns, tuple(response.keys())) 101 | self.assertEqual(data, tuple(response.values())) 102 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tests/unit/osc/v1/__init__.py -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tests/unit/osc/v1/fixture_data/__init__.py -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/client.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 NTT DATA 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import fixtures 16 | from keystoneauth1 import fixture 17 | from keystoneauth1 import loading 18 | from keystoneauth1 import session 19 | 20 | from tackerclient.v1_0 import client as proxy_client 21 | 22 | IDENTITY_URL = 'http://identityserver:5000/v3' 23 | TACKER_URL = 'http://nfv-orchestration' 24 | 25 | 26 | class ClientFixture(fixtures.Fixture): 27 | 28 | def __init__(self, requests_mock, identity_url=IDENTITY_URL, 29 | api_version='1'): 30 | super(ClientFixture, self).__init__() 31 | self.identity_url = identity_url 32 | self.client = None 33 | self.token = fixture.V2Token() 34 | self.token.set_scope() 35 | self.requests_mock = requests_mock 36 | self.discovery = fixture.V2Discovery(href=self.identity_url) 37 | s = self.token.add_service('nfv-orchestration') 38 | s.add_endpoint(TACKER_URL) 39 | self.api_version = api_version 40 | 41 | def setUp(self): 42 | super(ClientFixture, self).setUp() 43 | auth_url = '%s/tokens' % self.identity_url 44 | headers = {'X-Content-Type': 'application/json'} 45 | self.requests_mock.post(auth_url, json=self.token, headers=headers) 46 | self.requests_mock.get(self.identity_url, json=self.discovery, 47 | headers=headers) 48 | self.client = self.new_client() 49 | 50 | def new_client(self): 51 | self.session = session.Session() 52 | loader = loading.get_plugin_loader('password') 53 | self.session.auth = loader.load_from_options( 54 | auth_url=self.identity_url, username='xx', password='xx') 55 | 56 | return proxy_client.Client(service_type='nfv-orchestration', 57 | interface='public', 58 | endpoint_type='public', 59 | region_name='RegionOne', 60 | auth_url=self.identity_url, 61 | token=self.token.token_id, 62 | endpoint_url=TACKER_URL, 63 | api_version=self.api_version) 64 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/sample_vnf_package/Definitions/helloworld3_top.vnfd.yaml: -------------------------------------------------------------------------------- 1 | tosca_definitions_version: tosca_simple_yaml_1_0 2 | 3 | description: Sample VNF of NTT NS lab. 4 | 5 | imports: 6 | - etsi_nfv_sol001_common_types.yaml 7 | - etsi_nfv_sol001_vnfd_types.yaml 8 | - helloworld3_types.yaml 9 | - helloworld3_df_simple.yaml 10 | # - helloworld3_df_complex.yaml 11 | 12 | topology_template: 13 | inputs: 14 | selected_flavour: 15 | type: string 16 | description: VNF deployment flavour selected by the consumer. It is provided in the API 17 | 18 | node_templates: 19 | VNF: 20 | type: ntt.nslab.VNF 21 | properties: 22 | flavour_id: { get_input: selected_flavour } 23 | descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 24 | provider: NTT NS lab 25 | product_name: Sample VNF 26 | software_version: '1.0' 27 | descriptor_version: '1.0' 28 | vnfm_info: 29 | - Tacker 30 | requirements: 31 | #- virtual_link_external # mapped in lower-level templates 32 | #- virtual_link_internal # mapped in lower-level templates 33 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/sample_vnf_package/Definitions/helloworld3_types.yaml: -------------------------------------------------------------------------------- 1 | tosca_definitions_version: tosca_simple_yaml_1_0 2 | 3 | description: ntt.nslab.VNF type definition 4 | 5 | imports: 6 | - etsi_nfv_sol001_common_types.yaml 7 | - etsi_nfv_sol001_vnfd_types.yaml 8 | 9 | node_types: 10 | ntt.nslab.VNF: 11 | derived_from: tosca.nodes.nfv.VNF 12 | properties: 13 | descriptor_id: 14 | type: string 15 | constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 ] ] 16 | default: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 17 | descriptor_version: 18 | type: string 19 | constraints: [ valid_values: [ '1.0' ] ] 20 | default: '1.0' 21 | provider: 22 | type: string 23 | constraints: [ valid_values: [ 'NTT NS lab' ] ] 24 | default: 'NTT NS lab' 25 | product_name: 26 | type: string 27 | constraints: [ valid_values: [ 'Sample VNF' ] ] 28 | default: 'Sample VNF' 29 | software_version: 30 | type: string 31 | constraints: [ valid_values: [ '1.0' ] ] 32 | default: '1.0' 33 | vnfm_info: 34 | type: list 35 | entry_schema: 36 | type: string 37 | constraints: [ valid_values: [ Tacker ] ] 38 | default: [ Tacker ] 39 | flavour_id: 40 | type: string 41 | constraints: [ valid_values: [ simple ] ] 42 | default: simple 43 | flavour_description: 44 | type: string 45 | default: "" 46 | requirements: 47 | - virtual_link_external: 48 | capability: tosca.capabilities.nfv.VirtualLinkable 49 | - virtual_link_internal: 50 | capability: tosca.capabilities.nfv.VirtualLinkable 51 | interfaces: 52 | Vnflcm: 53 | type: tosca.interfaces.nfv.Vnflcm 54 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/sample_vnf_package/TOSCA-Metadata/TOSCA.meta: -------------------------------------------------------------------------------- 1 | TOSCA-Meta-File-Version: 1.0 2 | Created-by: Hiroyuki JO 3 | CSAR-Version: 1.1 4 | Entry-Definitions: Definitions/helloworld3_top.vnfd.yaml 5 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/sample_vnf_package_artifacts/Definitions/helloworld3_top.vnfd.yaml: -------------------------------------------------------------------------------- 1 | tosca_definitions_version: tosca_simple_yaml_1_0 2 | 3 | description: Sample VNF of NTT NS lab. 4 | 5 | imports: 6 | - etsi_nfv_sol001_common_types.yaml 7 | - etsi_nfv_sol001_vnfd_types.yaml 8 | - helloworld3_types.yaml 9 | - helloworld3_df_simple.yaml 10 | # - helloworld3_df_complex.yaml 11 | 12 | topology_template: 13 | inputs: 14 | selected_flavour: 15 | type: string 16 | description: VNF deployment flavour selected by the consumer. It is provided in the API 17 | 18 | node_templates: 19 | VNF: 20 | type: ntt.nslab.VNF 21 | properties: 22 | flavour_id: { get_input: selected_flavour } 23 | descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 24 | provider: NTT NS lab 25 | product_name: Sample VNF 26 | software_version: '1.0' 27 | descriptor_version: '1.0' 28 | vnfm_info: 29 | - Tacker 30 | requirements: 31 | #- virtual_link_external # mapped in lower-level templates 32 | #- virtual_link_internal # mapped in lower-level templates 33 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/sample_vnf_package_artifacts/Definitions/helloworld3_types.yaml: -------------------------------------------------------------------------------- 1 | tosca_definitions_version: tosca_simple_yaml_1_0 2 | 3 | description: ntt.nslab.VNF type definition 4 | 5 | imports: 6 | - etsi_nfv_sol001_common_types.yaml 7 | - etsi_nfv_sol001_vnfd_types.yaml 8 | 9 | node_types: 10 | ntt.nslab.VNF: 11 | derived_from: tosca.nodes.nfv.VNF 12 | properties: 13 | descriptor_id: 14 | type: string 15 | constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 ] ] 16 | default: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 17 | descriptor_version: 18 | type: string 19 | constraints: [ valid_values: [ '1.0' ] ] 20 | default: '1.0' 21 | provider: 22 | type: string 23 | constraints: [ valid_values: [ 'NTT NS lab' ] ] 24 | default: 'NTT NS lab' 25 | product_name: 26 | type: string 27 | constraints: [ valid_values: [ 'Sample VNF' ] ] 28 | default: 'Sample VNF' 29 | software_version: 30 | type: string 31 | constraints: [ valid_values: [ '1.0' ] ] 32 | default: '1.0' 33 | vnfm_info: 34 | type: list 35 | entry_schema: 36 | type: string 37 | constraints: [ valid_values: [ Tacker ] ] 38 | default: [ Tacker ] 39 | flavour_id: 40 | type: string 41 | constraints: [ valid_values: [ simple ] ] 42 | default: simple 43 | flavour_description: 44 | type: string 45 | default: "" 46 | requirements: 47 | - virtual_link_external: 48 | capability: tosca.capabilities.nfv.VirtualLinkable 49 | - virtual_link_internal: 50 | capability: tosca.capabilities.nfv.VirtualLinkable 51 | interfaces: 52 | Vnflcm: 53 | type: tosca.interfaces.nfv.Vnflcm 54 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/sample_vnf_package_artifacts/Scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Hello, World!" 4 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/fixture_data/sample_vnf_package_artifacts/TOSCA-Metadata/TOSCA.meta: -------------------------------------------------------------------------------- 1 | TOSCA-Meta-File-Version: 1.0 2 | Created-by: Dummy User 3 | CSAR-Version: 1.1 4 | Entry-Definitions: Definitions/helloworld3_top.vnfd.yaml 5 | 6 | Source: Scripts/install.sh 7 | Algorithm: SHA-256 8 | Hash: 27bbdb25d8f4ed6d07d6f6581b86515e8b2f0059b236ef7b6f50d6674b34f02a 9 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/vnflcm_fakes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 NTT DATA 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from oslo_utils.fixture import uuidsentinel 17 | from oslo_utils import uuidutils 18 | 19 | from tackerclient.osc import utils as tacker_osc_utils 20 | 21 | 22 | def vnf_instance_response(attrs=None, instantiation_state='NOT_INSTANTIATED'): 23 | """Create a fake vnf instance. 24 | 25 | :param Dictionary attrs: 26 | A dictionary with all attributes 27 | :return: 28 | A vnf instance dict 29 | """ 30 | attrs = attrs or {} 31 | 32 | # Set default attributes. 33 | dummy_vnf_instance = { 34 | "id": uuidsentinel.vnf_instance_id, 35 | "vnfInstanceName": "Fake-VNF-Instance", 36 | "vnfInstanceDescription": "Fake VNF", 37 | "vnfdId": uuidsentinel.vnf_package_vnfd_id, 38 | "vnfProvider": "NTT NS lab", 39 | "vnfProductName": "Sample VNF", 40 | "vnfSoftwareVersion": "1.0", 41 | "vnfdVersion": "1.0", 42 | "vnfPkgId": uuidsentinel.uuid, 43 | "_links": "vnflcm/v1/vnf_instances/" + uuidsentinel.vnf_instance_id + 44 | "/instantiate", 45 | "instantiationState": instantiation_state, 46 | "vnfConfigurableProperties": { 47 | "test": "test_value"}} 48 | if instantiation_state == 'INSTANTIATED': 49 | dummy_vnf_instance.update({ 50 | "vimConnectionInfo": [{ 51 | 'id': uuidsentinel.uuid, 52 | 'vimId': uuidsentinel.vimId, 53 | 'vimType': 'openstack', 54 | 'interfaceInfo': {'k': 'v'}, 55 | 'accessInfo': {'k': 'v'}, 56 | 'extra': {'k': 'v'} 57 | }], 58 | "instantiatedVnfInfo": { 59 | "flavourId": uuidsentinel.flavourId, 60 | "vnfState": "STARTED", 61 | "extCpInfo": [{ 62 | 'id': uuidsentinel.extCpInfo_uuid, 63 | 'cpdId': uuidsentinel.cpdId_uuid, 64 | 'cpProtocolInfo': [{ 65 | 'layerProtocol': 'IP_OVER_ETHERNET', 66 | 'ipOverEthernet': '{}' 67 | }], 68 | 'extLinkPortId': uuidsentinel.extLinkPortId_uuid, 69 | 'metadata': {'k': 'v'}, 70 | 'associatedVnfcCpId': uuidsentinel.associatedVnfcCpId_uuid 71 | }], 72 | "extVirtualLinkInfo": [{ 73 | 'id': uuidsentinel.extVirtualLinkInfo_uuid, 74 | 'resourceHandle': {}, 75 | 'extLinkPorts': [] 76 | }], 77 | "extManagedVirtualLinkInfo": [{ 78 | "id": uuidsentinel.extManagedVirtualLinkInfo_uuid, 79 | 'vnfVirtualLinkDescId': {}, 80 | 'networkResource': {}, 81 | 'vnfLinkPorts': [] 82 | }], 83 | "vnfcResourceInfo": [{ 84 | 'id': uuidsentinel.vnfcResourceInfo_uuid, 85 | 'vduId': uuidsentinel.vduId_uuid, 86 | 'computeResource': {}, 87 | 'storageResourceIds': [], 88 | 'reservationId': uuidsentinel.reservationId, 89 | }], 90 | "vnfVirtualLinkResourceInfo": [{ 91 | 'id': uuidsentinel.vnfVirtualLinkResourceInfo, 92 | 'vnfVirtualLinkDescId': 'VL4', 93 | 'networkResource': {}, 94 | 'reservationId': uuidsentinel.reservationId, 95 | 'vnfLinkPorts': [], 96 | 'metadata': {'k': 'v'} 97 | }], 98 | "virtualStorageResourceInfo": [{ 99 | 'id': uuidsentinel.virtualStorageResourceInfo, 100 | 'virtualStorageDescId': uuidsentinel.virtualStorageDescId, 101 | 'storageResource': {}, 102 | 'reservationId': uuidsentinel.reservationId, 103 | 'metadata': {'k': 'v'} 104 | }] 105 | }, 106 | "_links": { 107 | 'self': 'self_link', 108 | 'indicators': None, 109 | 'instantiate': 'instantiate_link' 110 | } 111 | }) 112 | 113 | # Overwrite default attributes. 114 | dummy_vnf_instance.update(attrs) 115 | 116 | return dummy_vnf_instance 117 | 118 | 119 | def get_vnflcm_data(vnf_instance, list_action=False, columns=None): 120 | """Get the vnf instance data. 121 | 122 | :return: 123 | A tuple object sorted based on the name of the columns. 124 | """ 125 | vnf = vnf_instance.copy() 126 | complex_attributes = ['vimConnectionInfo', 'instantiatedVnfInfo', '_links'] 127 | for attribute in complex_attributes: 128 | if vnf.get(attribute): 129 | vnf.update( 130 | {attribute: tacker_osc_utils.FormatComplexDataColumn( 131 | vnf[attribute])}) 132 | 133 | if list_action: 134 | for item in ['vnfInstanceDescription', 'vnfdVersion']: 135 | vnf.pop(item) 136 | 137 | # return the list of data as per column order 138 | if columns: 139 | return tuple([vnf[key] for key in columns]) 140 | 141 | return tuple([vnf[key] for key in sorted( 142 | vnf.keys())]) 143 | 144 | 145 | def create_vnf_instances(count=2): 146 | """Create multiple fake vnf instances. 147 | 148 | :param count: The number of vnf instances to fake 149 | :return: 150 | A list of fake vnf instances dictionary 151 | """ 152 | vnf_instances = [] 153 | for i in range(0, count): 154 | unique_id = uuidutils.generate_uuid() 155 | vnf_instances.append(vnf_instance_response(attrs={'id': unique_id})) 156 | return vnf_instances 157 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v1/vnflcm_op_occs_fakes.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from oslo_utils.fixture import uuidsentinel 14 | from oslo_utils import uuidutils 15 | 16 | from tackerclient.osc import utils as tacker_osc_utils 17 | 18 | 19 | def vnflcm_op_occ_response(attrs=None, action=''): 20 | """Create a fake vnflcm op occurrence. 21 | 22 | :param Dictionary attrs: 23 | A dictionary with all attributes 24 | :return: 25 | A vnf lcm op occs dict 26 | """ 27 | attrs = attrs or {} 28 | 29 | # Set default attributes. 30 | dummy_vnf_lcm_op_occ = { 31 | "id": uuidsentinel.vnflcm_op_occ_id, 32 | "operationState": "STARTING", 33 | "stateEnteredTime": "2018-12-22T16:59:45.187Z", 34 | "startTime": "2018-12-22T16:59:45.187Z", 35 | "vnfInstanceId": "376f37f3-d4e9-4d41-8e6a-9b0ec98695cc", 36 | "grantId": "", 37 | "operation": "INSTANTIATE", 38 | "isAutomaticInvocation": "true", 39 | "operationParams": { 40 | "flavourId": "default", 41 | "instantiationLevelId": "n-mme-min" 42 | }, 43 | "isCancelPending": "true", 44 | "cancelMode": "", 45 | "error": { 46 | "status": "500", 47 | "detail": "internal server error" 48 | }, 49 | "resourceChanges": [], 50 | "changedInfo": [], 51 | "changedExtConnectivity": [], 52 | "_links": { 53 | "self": "" 54 | } 55 | } 56 | 57 | if action == 'fail': 58 | fail_not_needed_columns = [ 59 | 'grantId', 'operationParams', 60 | 'cancelMode', 'resourceChanges', 'changedInfo', 61 | 'changedExtConnectivity'] 62 | 63 | for key in fail_not_needed_columns: 64 | del dummy_vnf_lcm_op_occ[key] 65 | 66 | # Overwrite default attributes. 67 | dummy_vnf_lcm_op_occ.update(attrs) 68 | 69 | return dummy_vnf_lcm_op_occ 70 | 71 | 72 | def get_vnflcm_op_occ_data(vnf_lcm_op_occ, columns=None): 73 | """Get the vnflcm op occurrence. 74 | 75 | :return: 76 | A tuple object sorted based on the name of the columns. 77 | """ 78 | complex_attributes = [ 79 | 'operationParams', 'error', 'resourceChanges', 80 | 'changedInfo', 'changedExtConnectivity', 'links'] 81 | 82 | for attribute in complex_attributes: 83 | if vnf_lcm_op_occ.get(attribute): 84 | vnf_lcm_op_occ.update( 85 | {attribute: tacker_osc_utils.FormatComplexDataColumn( 86 | vnf_lcm_op_occ[attribute])}) 87 | 88 | # return the list of data as per column order 89 | if columns: 90 | return tuple([vnf_lcm_op_occ[key] for key in columns]) 91 | 92 | return tuple([vnf_lcm_op_occ[key] for key in sorted( 93 | vnf_lcm_op_occ.keys())]) 94 | 95 | 96 | def create_vnflcm_op_occs(count=2): 97 | """Create multiple fake vnflcm op occs. 98 | 99 | :param count: The number of vnflcm op occs to fake 100 | :return: 101 | A list of fake vnflcm op occs dictionary 102 | """ 103 | vnflcm_op_occs = [] 104 | for i in range(0, count): 105 | unique_id = uuidutils.generate_uuid() 106 | vnflcm_op_occs.append(vnflcm_op_occ_response(attrs={'id': unique_id})) 107 | return vnflcm_op_occs 108 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tests/unit/osc/v2/__init__.py -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v2/test_vnfpm_report.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Fujitsu 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import os 17 | 18 | from oslo_utils.fixture import uuidsentinel 19 | from unittest import mock 20 | 21 | from tackerclient.common import exceptions 22 | from tackerclient.osc.v2.vnfpm import vnfpm_report 23 | from tackerclient.tests.unit.osc import base 24 | from tackerclient.tests.unit.osc.v1.fixture_data import client 25 | from tackerclient.tests.unit.osc.v2 import vnfpm_report_fakes 26 | 27 | 28 | class TestVnfPmReport(base.FixturedTestCase): 29 | client_fixture_class = client.ClientFixture 30 | 31 | def setUp(self): 32 | super(TestVnfPmReport, self).setUp() 33 | self.url = client.TACKER_URL 34 | self.header = {'content-type': 'application/json'} 35 | self.app = mock.Mock() 36 | self.app_args = mock.Mock() 37 | self.client_manager = self.cs 38 | self.app.client_manager.tackerclient = self.client_manager 39 | 40 | 41 | def _get_columns_vnfpm_report(): 42 | columns = ['Entries'] 43 | return columns 44 | 45 | 46 | class TestShowVnfPmReport(TestVnfPmReport): 47 | 48 | def setUp(self): 49 | super(TestShowVnfPmReport, self).setUp() 50 | self.show_vnf_pm_reports = vnfpm_report.ShowVnfPmReport( 51 | self.app, self.app_args, cmd_name='vnfpm report show') 52 | 53 | def test_take_action(self): 54 | """Test of take_action()""" 55 | vnfpm_report_obj = vnfpm_report_fakes.vnf_pm_report_response() 56 | vnf_pm_job_id = uuidsentinel.vnf_pm_job_id 57 | vnf_pm_report_id = uuidsentinel.vnfpm_report_obj 58 | arg_list = [vnf_pm_job_id, vnf_pm_report_id] 59 | verify_list = [ 60 | ('vnf_pm_job_id', vnf_pm_job_id), 61 | ('vnf_pm_report_id', vnf_pm_report_id) 62 | ] 63 | 64 | # command param 65 | parsed_args = self.check_parser( 66 | self.show_vnf_pm_reports, arg_list, verify_list) 67 | url = os.path.join( 68 | self.url, 'vnfpm/v2/pm_jobs', vnf_pm_job_id, 69 | 'reports', vnf_pm_report_id) 70 | 71 | self.requests_mock.register_uri( 72 | 'GET', url, headers=self.header, json=vnfpm_report_obj) 73 | 74 | columns, data = (self.show_vnf_pm_reports.take_action(parsed_args)) 75 | 76 | self.assertCountEqual(_get_columns_vnfpm_report(), columns) 77 | 78 | _, attributes = vnfpm_report._get_columns(vnfpm_report_obj) 79 | expected_data = vnfpm_report_fakes.get_vnfpm_report_data( 80 | vnfpm_report_obj, columns=attributes) 81 | 82 | print(f'123, {expected_data}') 83 | print(f'456, {data}') 84 | self.assertListItemsEqual(expected_data, data) 85 | 86 | def test_take_action_vnf_pm_report_id_not_found(self): 87 | """Test if vnf-pm-report-id does not find.""" 88 | vnf_pm_job_id = uuidsentinel.vnf_pm_job_id 89 | vnf_pm_report_id = uuidsentinel.vnf_pm_report_id 90 | arg_list = [vnf_pm_job_id, vnf_pm_report_id] 91 | verify_list = [ 92 | ('vnf_pm_job_id', vnf_pm_job_id), 93 | ('vnf_pm_report_id', vnf_pm_report_id) 94 | ] 95 | 96 | # command param 97 | parsed_args = self.check_parser( 98 | self.show_vnf_pm_reports, arg_list, verify_list) 99 | 100 | url = os.path.join( 101 | self.url, 'vnfpm/v2/pm_jobs', vnf_pm_job_id, 102 | 'reports', vnf_pm_report_id) 103 | self.requests_mock.register_uri( 104 | 'GET', url, headers=self.header, status_code=404, json={}) 105 | 106 | self.assertRaises(exceptions.TackerClientException, 107 | self.show_vnf_pm_reports.take_action, 108 | parsed_args) 109 | 110 | def test_take_action_internal_server_error(self): 111 | """Test for internal server error.""" 112 | vnf_pm_job_id = uuidsentinel.vnf_pm_job_id 113 | vnf_pm_report_id = uuidsentinel.vnf_pm_report_id 114 | arg_list = [vnf_pm_job_id, vnf_pm_report_id] 115 | verify_list = [ 116 | ('vnf_pm_job_id', vnf_pm_job_id), 117 | ('vnf_pm_report_id', vnf_pm_report_id) 118 | ] 119 | # command param 120 | parsed_args = self.check_parser( 121 | self.show_vnf_pm_reports, arg_list, verify_list) 122 | 123 | url = os.path.join( 124 | self.url, 'vnfpm/v2/pm_jobs', vnf_pm_job_id, 125 | 'reports', vnf_pm_report_id) 126 | self.requests_mock.register_uri( 127 | 'GET', url, headers=self.header, status_code=500, json={}) 128 | 129 | self.assertRaises(exceptions.TackerClientException, 130 | self.show_vnf_pm_reports.take_action, 131 | parsed_args) 132 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v2/vnffm_alarm_fakes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Fujitsu 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from oslo_utils import uuidutils 17 | 18 | from tackerclient.osc import utils as tacker_osc_utils 19 | 20 | 21 | def create_vnf_fm_alarms(count=2): 22 | """Create multiple fake vnf packages. 23 | 24 | :param int count: 25 | The number of vnf_fm_alarms to fake 26 | :return: 27 | A list of fake vnf fm alarms dictionary 28 | """ 29 | vnf_fm_alarms = [] 30 | for i in range(0, count): 31 | unique_id = uuidutils.generate_uuid() 32 | vnf_fm_alarms.append(vnf_fm_alarm_response(attrs={'id': unique_id})) 33 | return vnf_fm_alarms 34 | 35 | 36 | def vnf_fm_alarm_response(attrs=None, action=None): 37 | """Create a fake vnf fm alarm. 38 | 39 | :param Dictionary attrs: 40 | A dictionary with all attributes 41 | :return: 42 | A FakeVnfFmAlarm dict 43 | """ 44 | 45 | if action == 'update': 46 | fake_vnf_fm_alarm = { 47 | "ackState": "UNACKNOWLEDGED" 48 | } 49 | return fake_vnf_fm_alarm 50 | 51 | attrs = attrs or {} 52 | # Set default attributes. 53 | fake_vnf_fm_alarm = { 54 | "id": "78a39661-60a8-4824-b989-88c1b0c3534a", 55 | "managedObjectId": "c61314d0-f583-4ab3-a457-46426bce02d3", 56 | "vnfcInstanceIds": "0e5f3086-4e79-47ed-a694-54c29155fa26", 57 | "rootCauseFaultyResource": { 58 | "faultyResource": { 59 | "vimConnectionId": "0d57e928-86a4-4445-a4bd-1634edae73f3", 60 | "resourceId": "4e6ccbe1-38ec-4b1b-a278-64de09ba01b3", 61 | "vimLevelResourceType": "OS::Nova::Server" 62 | }, 63 | "faultyResourceType": "COMPUTE" 64 | }, 65 | "alarmRaisedTime": "2021-09-03 10:21:03", 66 | "alarmChangedTime": "2021-09-04 10:21:03", 67 | "alarmClearedTime": "2021-09-05 10:21:03", 68 | "alarmAcknowledgedTime": "2021-09-06 10:21:03", 69 | "ackState": "UNACKNOWLEDGED", 70 | "perceivedSeverity": "WARNING", 71 | "eventTime": "2021-09-07 10:06:03", 72 | "eventType": "EQUIPMENT_ALARM", 73 | "faultType": "Fault Type", 74 | "probableCause": "The server cannot be connected.", 75 | "isRootCause": False, 76 | "correlatedAlarmIds": [ 77 | "c88b624e-e997-4b17-b674-10ca2bab62e0", 78 | "c16d41fd-12e2-49a6-bb17-72faf702353f" 79 | ], 80 | "faultDetails": [ 81 | "Fault", 82 | "Details" 83 | ], 84 | "_links": { 85 | "self": { 86 | "href": "/vnffm/v1/alarms/" 87 | "78a39661-60a8-4824-b989-88c1b0c3534a" 88 | }, 89 | "objectInstance": { 90 | "href": "/vnflcm/v1/vnf_instances/" 91 | "0e5f3086-4e79-47ed-a694-54c29155fa26" 92 | } 93 | } 94 | } 95 | 96 | # Overwrite default attributes. 97 | fake_vnf_fm_alarm.update(attrs) 98 | 99 | return fake_vnf_fm_alarm 100 | 101 | 102 | def get_vnffm_alarm_data(vnf_fm_alarm, columns=None): 103 | """Get the vnffm alarm. 104 | 105 | :return: 106 | A tuple object sorted based on the name of the columns. 107 | """ 108 | complex_attributes = [ 109 | 'vnfcInstanceIds', 110 | 'rootCauseFaultyResource', 111 | 'correlatedAlarmIds', 112 | 'faultDetails', 113 | '_links' 114 | ] 115 | 116 | for attribute in complex_attributes: 117 | if vnf_fm_alarm.get(attribute): 118 | vnf_fm_alarm.update( 119 | {attribute: tacker_osc_utils.FormatComplexDataColumn( 120 | vnf_fm_alarm[attribute])}) 121 | 122 | # return the list of data as per column order 123 | if columns: 124 | return tuple([vnf_fm_alarm[key] for key in columns]) 125 | 126 | return tuple([vnf_fm_alarm[key] for key in sorted( 127 | vnf_fm_alarm.keys())]) 128 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v2/vnffm_sub_fakes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Fujitsu 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from oslo_utils import uuidutils 17 | 18 | from tackerclient.osc import utils as tacker_osc_utils 19 | 20 | 21 | def create_vnf_fm_subs(count=2): 22 | """Create multiple fake vnf packages. 23 | 24 | :param int count: 25 | The number of vnf_fm_subs to fake 26 | :return: 27 | A list of fake vnf fm subs dictionary 28 | """ 29 | vnf_fm_subs = [] 30 | for i in range(0, count): 31 | unique_id = uuidutils.generate_uuid() 32 | vnf_fm_subs.append(vnf_fm_sub_response(attrs={'id': unique_id})) 33 | return vnf_fm_subs 34 | 35 | 36 | def vnf_fm_sub_response(attrs=None): 37 | """Create a fake vnf fm sub. 38 | 39 | :param Dictionary attrs: 40 | A dictionary with all attributes 41 | :return: 42 | A FakeVnfFmAlarm dict 43 | """ 44 | 45 | attrs = attrs or {} 46 | # Set default attributes. 47 | fake_vnf_fm_sub = { 48 | "id": "78a39661-60a8-4824-b989-88c1b0c3534a", 49 | "filter": { 50 | "vnfInstanceSubscriptionFilter": { 51 | "vnfdIds": [ 52 | "dummy-vnfdId-1" 53 | ], 54 | "vnfProductsFromProviders": [ 55 | { 56 | "vnfProvider": "dummy-vnfProvider-1", 57 | "vnfProducts": [ 58 | { 59 | "vnfProductName": "dummy-vnfProductName-1-1", 60 | "versions": [ 61 | { 62 | "vnfSoftwareVersion": 1.0, 63 | "vnfdVersions": [1.0, 2.0] 64 | } 65 | ] 66 | } 67 | ] 68 | } 69 | ], 70 | "vnfInstanceIds": [ 71 | "dummy-vnfInstanceId-1" 72 | ], 73 | "vnfInstanceNames": [ 74 | "dummy-vnfInstanceName-1" 75 | ] 76 | }, 77 | "notificationTypes": [ 78 | "AlarmNotification" 79 | ], 80 | "faultyResourceTypes": [ 81 | "COMPUTE" 82 | ], 83 | "perceivedSeverities": [ 84 | "WARNING" 85 | ], 86 | "eventTypes": [ 87 | "EQUIPMENT_ALARM" 88 | ], 89 | "probableCauses": [ 90 | "The server cannot be connected." 91 | ] 92 | }, 93 | "callbackUri": "/nfvo/notify/alarm", 94 | "_links": { 95 | "self": { 96 | "href": "/vnffm/v1/subscriptions/" 97 | "78a39661-60a8-4824-b989-88c1b0c3534a" 98 | } 99 | } 100 | } 101 | 102 | # Overwrite default attributes. 103 | fake_vnf_fm_sub.update(attrs) 104 | 105 | return fake_vnf_fm_sub 106 | 107 | 108 | def get_vnffm_sub_data(vnf_fm_sub, columns=None): 109 | """Get the vnffm sub. 110 | 111 | :return: 112 | A tuple object sorted based on the name of the columns. 113 | """ 114 | complex_attributes = ['filter', '_links'] 115 | 116 | for attribute in complex_attributes: 117 | if vnf_fm_sub.get(attribute): 118 | vnf_fm_sub.update( 119 | {attribute: tacker_osc_utils.FormatComplexDataColumn( 120 | vnf_fm_sub[attribute])}) 121 | 122 | # return the list of data as per column order 123 | if columns: 124 | return tuple([vnf_fm_sub[key] for key in columns]) 125 | 126 | return tuple([vnf_fm_sub[key] for key in sorted( 127 | vnf_fm_sub.keys())]) 128 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v2/vnfpm_job_fakes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Fujitsu 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from oslo_utils import uuidutils 17 | 18 | from tackerclient.osc import utils as tacker_osc_utils 19 | 20 | 21 | def create_vnf_pm_jobs(count=2): 22 | """Create multiple fake vnf pm jobs. 23 | 24 | :param int count: 25 | The number of vnf_pm_jobs to fake 26 | :return: 27 | A list of fake vnf pm jobs dictionary 28 | """ 29 | vnf_pm_jobs = [] 30 | for i in range(0, count): 31 | unique_id = uuidutils.generate_uuid() 32 | vnf_pm_jobs.append(vnf_pm_job_response(attrs={'id': unique_id})) 33 | return {'vnf_pm_jobs': vnf_pm_jobs} 34 | 35 | 36 | def vnf_pm_job_response(attrs=None, action=None): 37 | """Create a fake vnf pm job. 38 | 39 | :param Dictionary attrs: 40 | A dictionary with all attributes 41 | :return: 42 | A pm job dict 43 | """ 44 | if action == 'update': 45 | fake_vnf_pm_job = { 46 | "callbackUri": "/nfvo/notify/job" 47 | } 48 | return fake_vnf_pm_job 49 | 50 | attrs = attrs or {} 51 | # Set default attributes. 52 | fake_vnf_pm_job = { 53 | "id": "2bb72d78-b1d9-48fe-8c64-332654ffeb5d", 54 | "objectType": "VNFC", 55 | "objectInstanceIds": [ 56 | "object-instance-id-1" 57 | ], 58 | "subObjectInstanceIds": [ 59 | "sub-object-instance-id-2" 60 | ], 61 | "criteria": { 62 | "performanceMetric": [ 63 | "VCpuUsageMeanVnf.object-instance-id-1" 64 | ], 65 | "performanceMetricGroup": [ 66 | "VirtualisedComputeResource" 67 | ], 68 | "collectionPeriod": 500, 69 | "reportingPeriod": 1000, 70 | "reportingBoundary": "2022/07/25 10:43:55" 71 | }, 72 | "callbackUri": "/nfvo/notify/job", 73 | "reports": [{ 74 | "href": "/vnfpm/v2/pm_jobs/2bb72d78-b1d9-48fe-8c64-332654ffeb5d/" 75 | "reports/09d46aed-3ec2-45d9-bfa2-add431e069b3", 76 | "readyTime": "2022/07/25 10:43:55", 77 | "expiryTime": "2022/07/25 10:43:55", 78 | "fileSize": 9999 79 | }], 80 | "_links": { 81 | "self": { 82 | "href": "/vnfpm/v2/pm_jobs/" 83 | "78a39661-60a8-4824-b989-88c1b0c3534a" 84 | }, 85 | "objects": [{ 86 | "href": "/vnflcm/v1/vnf_instances/" 87 | "0e5f3086-4e79-47ed-a694-54c29155fa26" 88 | }] 89 | } 90 | } 91 | 92 | # Overwrite default attributes. 93 | fake_vnf_pm_job.update(attrs) 94 | 95 | return fake_vnf_pm_job 96 | 97 | 98 | def get_vnfpm_job_data(vnf_pm_job, columns=None): 99 | """Get the vnfpm job. 100 | 101 | :return: 102 | A tuple object sorted based on the name of the columns. 103 | """ 104 | complex_attributes = [ 105 | 'objectInstanceIds', 'subObjectInstanceIds', 106 | 'criteria', 'reports', '_links', 107 | 'authentication' 108 | ] 109 | 110 | for attribute in complex_attributes: 111 | if vnf_pm_job.get(attribute): 112 | vnf_pm_job.update( 113 | {attribute: tacker_osc_utils.FormatComplexDataColumn( 114 | vnf_pm_job[attribute])}) 115 | 116 | # return the list of data as per column order 117 | if columns is None: 118 | columns = sorted(vnf_pm_job.keys()) 119 | return tuple([vnf_pm_job[key] for key in columns]) 120 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v2/vnfpm_report_fakes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Fujitsu 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from tackerclient.osc import utils as tacker_osc_utils 17 | 18 | 19 | def vnf_pm_report_response(attrs=None): 20 | """Create a fake vnf pm report. 21 | 22 | :param Dictionary attrs: 23 | A dictionary with all attributes 24 | :return: 25 | A pm report dict 26 | """ 27 | 28 | attrs = attrs or {} 29 | # Set default attributes. 30 | fake_vnf_pm_report = { 31 | "entries": [ 32 | { 33 | "objectType": "VNFC", 34 | "objectInstanceId": "2bb72d78-b1d9-48fe-8c64-332654ffeb5d", 35 | "subObjectInstanceId": "09d46aed-3ec2-45d9-bfa2-add431e069b3", 36 | "performanceMetric": 37 | "VCpuUsagePeakVnf.2bb72d78-b1d9-48fe-8c64-332654ffeb5d,", 38 | "performanceValues": [ 39 | { 40 | "timeStamp": "2022/07/27 08:58:58", 41 | "value": "1.88", 42 | "context": { 43 | "key": "value" 44 | } 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | 51 | # Overwrite default attributes. 52 | fake_vnf_pm_report.update(attrs) 53 | 54 | return fake_vnf_pm_report 55 | 56 | 57 | def get_vnfpm_report_data(vnf_pm_report, columns=None): 58 | """Get the vnfpm report. 59 | 60 | :return: 61 | A tuple object sorted based on the name of the columns. 62 | """ 63 | attribute = 'entries' 64 | 65 | if vnf_pm_report.get(attribute): 66 | vnf_pm_report.update( 67 | {attribute: tacker_osc_utils.FormatComplexDataColumn( 68 | vnf_pm_report[attribute])}) 69 | 70 | # return the list of data as per column order 71 | if columns is None: 72 | columns = sorted(vnf_pm_report.keys()) 73 | return tuple([vnf_pm_report[key] for key in columns]) 74 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/osc/v2/vnfpm_threshold_fakes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2023 Fujitsu 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from oslo_utils import uuidutils 17 | 18 | from tackerclient.osc import utils as tacker_osc_utils 19 | 20 | 21 | def create_vnf_pm_thresholds(count=2): 22 | """Create multiple fake vnf pm thresholds. 23 | 24 | :param int count: 25 | The number of vnf_pm_thresholds to fake 26 | :return: 27 | A list of fake vnf pm thresholds dictionary 28 | """ 29 | vnf_pm_thresholds = [] 30 | for _ in range(0, count): 31 | unique_id = uuidutils.generate_uuid() 32 | vnf_pm_thresholds.append(vnf_pm_threshold_response( 33 | attrs={'id': unique_id})) 34 | return vnf_pm_thresholds 35 | 36 | 37 | def vnf_pm_threshold_response(attrs=None, action=None): 38 | """Create a fake vnf pm threshold. 39 | 40 | :param Dictionary attrs: 41 | A dictionary with all attributes 42 | :param String action: 43 | The operation performed on threshold 44 | :return: 45 | A pm threshold dict 46 | """ 47 | if action == 'update': 48 | fake_vnf_pm_threshold = { 49 | "callbackUri": "/nfvo/notify/threshold", 50 | } 51 | return fake_vnf_pm_threshold 52 | 53 | attrs = attrs or {} 54 | # Set default attributes. 55 | fake_vnf_pm_threshold = { 56 | "id": "2bb72d78-b1d9-48fe-8c64-332654ffeb5d", 57 | "objectType": "Vnfc", 58 | "objectInstanceId": "object-instance-id-1", 59 | "subObjectInstanceIds": [ 60 | "sub-object-instance-id-2" 61 | ], 62 | "criteria": { 63 | "performanceMetric": "VCpuUsageMeanVnf.object-instance-id-1", 64 | "thresholdType": "SIMPLE", 65 | "simpleThresholdDetails": { 66 | "thresholdValue": 500.5, 67 | "hysteresis": 10.5 68 | } 69 | }, 70 | "callbackUri": "/nfvo/notify/threshold", 71 | "_links": { 72 | "self": { 73 | "href": "/vnfpm/v2/thresholds/" 74 | "78a39661-60a8-4824-b989-88c1b0c3534a" 75 | }, 76 | "object": { 77 | "href": "/vnflcm/v1/vnf_instances/" 78 | "0e5f3086-4e79-47ed-a694-54c29155fa26" 79 | } 80 | } 81 | } 82 | 83 | # Overwrite default attributes. 84 | fake_vnf_pm_threshold.update(attrs) 85 | 86 | return fake_vnf_pm_threshold 87 | 88 | 89 | def get_vnfpm_threshold_data(vnf_pm_threshold, columns=None): 90 | """Get the vnfpm threshold. 91 | 92 | :param Dictionary vnf_pm_threshold: 93 | A dictionary with vnf_pm_threshold 94 | :param List columns: 95 | A list of column names 96 | :return: 97 | A tuple object sorted based on the name of the columns. 98 | """ 99 | complex_attributes = ['subObjectInstanceIds', 100 | 'criteria', '_links', 'authentication'] 101 | 102 | for attribute in complex_attributes: 103 | if vnf_pm_threshold.get(attribute): 104 | vnf_pm_threshold.update( 105 | {attribute: tacker_osc_utils.FormatComplexDataColumn( 106 | vnf_pm_threshold[attribute])}) 107 | 108 | # return the list of data as per column order 109 | if columns is None: 110 | columns = sorted(vnf_pm_threshold.keys()) 111 | return tuple([vnf_pm_threshold[key] for key in columns]) 112 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/test_casual_args.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 OpenStack Foundation. 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | # 16 | 17 | import testtools 18 | 19 | from tackerclient.common import exceptions 20 | from tackerclient.tacker import v1_0 as tackerV10 21 | 22 | 23 | class CLITestArgs(testtools.TestCase): 24 | 25 | def test_empty(self): 26 | _mydict = tackerV10.parse_args_to_dict([]) 27 | self.assertEqual({}, _mydict) 28 | 29 | def test_default_bool(self): 30 | _specs = ['--my_bool', '--arg1', 'value1'] 31 | _mydict = tackerV10.parse_args_to_dict(_specs) 32 | self.assertTrue(_mydict['my_bool']) 33 | 34 | def test_bool_true(self): 35 | _specs = ['--my-bool', 'type=bool', 'true', '--arg1', 'value1'] 36 | _mydict = tackerV10.parse_args_to_dict(_specs) 37 | self.assertTrue(_mydict['my_bool']) 38 | 39 | def test_bool_false(self): 40 | _specs = ['--my_bool', 'type=bool', 'false', '--arg1', 'value1'] 41 | _mydict = tackerV10.parse_args_to_dict(_specs) 42 | self.assertFalse(_mydict['my_bool']) 43 | 44 | def test_nargs(self): 45 | _specs = ['--tag', 'x', 'y', '--arg1', 'value1'] 46 | _mydict = tackerV10.parse_args_to_dict(_specs) 47 | self.assertIn('x', _mydict['tag']) 48 | self.assertIn('y', _mydict['tag']) 49 | 50 | def test_badarg(self): 51 | _specs = ['--tag=t', 'x', 'y', '--arg1', 'value1'] 52 | self.assertRaises(exceptions.CommandError, 53 | tackerV10.parse_args_to_dict, _specs) 54 | 55 | def test_badarg_with_minus(self): 56 | _specs = ['--arg1', 'value1', '-D'] 57 | self.assertRaises(exceptions.CommandError, 58 | tackerV10.parse_args_to_dict, _specs) 59 | 60 | def test_goodarg_with_minus_number(self): 61 | _specs = ['--arg1', 'value1', '-1', '-1.0'] 62 | _mydict = tackerV10.parse_args_to_dict(_specs) 63 | self.assertEqual(['value1', '-1', '-1.0'], 64 | _mydict['arg1']) 65 | 66 | def test_badarg_duplicate(self): 67 | _specs = ['--tag=t', '--arg1', 'value1', '--arg1', 'value1'] 68 | self.assertRaises(exceptions.CommandError, 69 | tackerV10.parse_args_to_dict, _specs) 70 | 71 | def test_badarg_early_type_specification(self): 72 | _specs = ['type=dict', 'key=value'] 73 | self.assertRaises(exceptions.CommandError, 74 | tackerV10.parse_args_to_dict, _specs) 75 | 76 | def test_arg(self): 77 | _specs = ['--tag=t', '--arg1', 'value1'] 78 | self.assertEqual('value1', 79 | tackerV10.parse_args_to_dict(_specs)['arg1']) 80 | 81 | def test_dict_arg(self): 82 | _specs = ['--tag=t', '--arg1', 'type=dict', 'key1=value1,key2=value2'] 83 | arg1 = tackerV10.parse_args_to_dict(_specs)['arg1'] 84 | self.assertEqual('value1', arg1['key1']) 85 | self.assertEqual('value2', arg1['key2']) 86 | 87 | def test_dict_arg_with_attribute_named_type(self): 88 | _specs = ['--tag=t', '--arg1', 'type=dict', 'type=value1,key2=value2'] 89 | arg1 = tackerV10.parse_args_to_dict(_specs)['arg1'] 90 | self.assertEqual('value1', arg1['type']) 91 | self.assertEqual('value2', arg1['key2']) 92 | 93 | def test_list_of_dict_arg(self): 94 | _specs = ['--tag=t', '--arg1', 'type=dict', 95 | 'list=true', 'key1=value1,key2=value2'] 96 | arg1 = tackerV10.parse_args_to_dict(_specs)['arg1'] 97 | self.assertEqual('value1', arg1[0]['key1']) 98 | self.assertEqual('value2', arg1[0]['key2']) 99 | 100 | def test_clear_action(self): 101 | _specs = ['--anyarg', 'action=clear'] 102 | args = tackerV10.parse_args_to_dict(_specs) 103 | self.assertIsNone(args['anyarg']) 104 | 105 | def test_bad_values_str(self): 106 | _specs = ['--strarg', 'type=str'] 107 | self.assertRaises(exceptions.CommandError, 108 | tackerV10.parse_args_to_dict, _specs) 109 | 110 | def test_bad_values_list(self): 111 | _specs = ['--listarg', 'list=true', 'type=str'] 112 | self.assertRaises(exceptions.CommandError, 113 | tackerV10.parse_args_to_dict, _specs) 114 | _specs = ['--listarg', 'type=list'] 115 | self.assertRaises(exceptions.CommandError, 116 | tackerV10.parse_args_to_dict, _specs) 117 | _specs = ['--listarg', 'type=list', 'action=clear'] 118 | self.assertRaises(exceptions.CommandError, 119 | tackerV10.parse_args_to_dict, _specs) 120 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/test_command_meta.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Intel Corporation 2 | # All Rights Reserved. 3 | # 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | import logging 18 | 19 | import testtools 20 | 21 | from tackerclient.tacker import v1_0 as tackerV10 22 | 23 | 24 | class TestCommandMeta(testtools.TestCase): 25 | def test_tacker_command_meta_defines_log(self): 26 | class FakeCommand(tackerV10.TackerCommand): 27 | pass 28 | 29 | self.assertTrue(hasattr(FakeCommand, 'log')) 30 | self.assertIsInstance(FakeCommand.log, logging.getLoggerClass()) 31 | self.assertEqual(FakeCommand.log.name, __name__ + ".FakeCommand") 32 | 33 | def test_tacker_command_log_defined_explicitly(self): 34 | class FakeCommand(tackerV10.TackerCommand): 35 | log = None 36 | 37 | self.assertTrue(hasattr(FakeCommand, 'log')) 38 | self.assertIsNone(FakeCommand.log) 39 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/test_http.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 OpenStack Foundation. 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import testtools 17 | from unittest import mock 18 | 19 | from tackerclient.client import HTTPClient 20 | from tackerclient.common import exceptions 21 | from tackerclient.tests.unit.test_cli10 import MyResp 22 | 23 | 24 | AUTH_TOKEN = 'test_token' 25 | END_URL = 'test_url' 26 | METHOD = 'GET' 27 | URL = 'http://test.test:1234/v1.0/test' 28 | headers = {'User-Agent': 'python-tackerclient'} 29 | 30 | 31 | class TestHTTPClient(testtools.TestCase): 32 | 33 | def setUp(self): 34 | 35 | super(TestHTTPClient, self).setUp() 36 | self.addCleanup(mock.patch.stopall) 37 | self.http = HTTPClient(token=AUTH_TOKEN, endpoint_url=END_URL) 38 | 39 | @mock.patch('tackerclient.client.HTTPClient.request') 40 | def test_request_error(self, mock_request): 41 | 42 | mock_request.side_effect = Exception('error msg') 43 | self.assertRaises( 44 | exceptions.ConnectionFailed, 45 | self.http._cs_request, 46 | URL, METHOD 47 | ) 48 | 49 | @mock.patch('tackerclient.client.HTTPClient.request') 50 | def test_request_success(self, mock_request): 51 | 52 | rv_should_be = MyResp(200), 'test content' 53 | mock_request.return_value = rv_should_be 54 | self.assertEqual(rv_should_be, self.http._cs_request(URL, METHOD)) 55 | 56 | @mock.patch('tackerclient.client.HTTPClient.request') 57 | def test_request_unauthorized(self, mock_request): 58 | 59 | mock_request.return_value = MyResp(401), 'unauthorized message' 60 | 61 | e = self.assertRaises(exceptions.Unauthorized, 62 | self.http._cs_request, URL, METHOD) 63 | self.assertEqual('unauthorized message', str(e)) 64 | mock_request.assert_called_with(URL, METHOD, headers=headers) 65 | 66 | @mock.patch('tackerclient.client.HTTPClient.request') 67 | def test_request_forbidden_is_returned_to_caller(self, mock_request): 68 | 69 | rv_should_be = MyResp(403), 'forbidden message' 70 | mock_request.return_value = rv_should_be 71 | self.assertEqual(rv_should_be, self.http._cs_request(URL, METHOD)) 72 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/test_ssl.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 OpenStack Foundation. 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from unittest import mock 17 | 18 | import fixtures 19 | from keystoneclient import session 20 | import requests 21 | import testtools 22 | 23 | from tackerclient import client 24 | from tackerclient.common import clientmanager 25 | from tackerclient.common import exceptions 26 | from tackerclient import shell as openstack_shell 27 | 28 | 29 | AUTH_TOKEN = 'test_token' 30 | END_URL = 'test_url' 31 | METHOD = 'GET' 32 | URL = 'http://test.test:1234/v1.0/' 33 | CA_CERT = '/tmp/test/path' 34 | DEFAULT_API_VERSION = '1.0' 35 | 36 | 37 | class TestSSL(testtools.TestCase): 38 | def setUp(self): 39 | super(TestSSL, self).setUp() 40 | 41 | self.useFixture(fixtures.EnvironmentVariable('OS_TOKEN', AUTH_TOKEN)) 42 | self.useFixture(fixtures.EnvironmentVariable('OS_URL', END_URL)) 43 | self.addCleanup(mock.patch.stopall) 44 | 45 | def _test_verify_client_manager(self, cacert): 46 | with mock.patch.object(session, 'Session'), \ 47 | mock.patch.object(clientmanager, 'ClientManager') as mock_cmgr: 48 | 49 | mock_cmgr.return_value = 0 50 | shell = openstack_shell.TackerShell(DEFAULT_API_VERSION) 51 | shell.options = mock.Mock() 52 | auth_session = shell._get_keystone_session() 53 | 54 | shell.run(cacert) 55 | 56 | mock_cmgr.assert_called_with( 57 | api_version={'nfv-orchestration': '1.0'}, 58 | auth=auth_session.auth, auth_strategy='keystone', 59 | auth_url='', ca_cert=CA_CERT, endpoint_type='publicURL', 60 | insecure=False, log_credentials=True, password='', 61 | raise_errors=False, region_name='', retries=0, 62 | service_type='nfv-orchestration', session=auth_session, 63 | tenant_id='', tenant_name='', timeout=None, 64 | token='test_token', url='test_url', user_id='', username='') 65 | 66 | def test_ca_cert_passed(self): 67 | cacert = ['--os-cacert', CA_CERT] 68 | self._test_verify_client_manager(cacert) 69 | 70 | def test_ca_cert_passed_as_env_var(self): 71 | self.useFixture(fixtures.EnvironmentVariable('OS_CACERT', CA_CERT)) 72 | self._test_verify_client_manager([]) 73 | 74 | @mock.patch.object(client.HTTPClient, 'request') 75 | def test_proper_exception_is_raised_when_cert_validation_fails(self, 76 | mock_req): 77 | http = client.HTTPClient(token=AUTH_TOKEN, endpoint_url=END_URL) 78 | mock_req.side_effect = requests.exceptions.SSLError() 79 | self.assertRaises( 80 | exceptions.SslCertificateValidationError, 81 | http._cs_request, 82 | URL, METHOD 83 | ) 84 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/test_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Yahoo! Inc. 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import testtools 17 | 18 | from tackerclient.common import exceptions 19 | from tackerclient.common import utils 20 | 21 | 22 | class TestUtils(testtools.TestCase): 23 | def test_string_to_bool_true(self): 24 | self.assertTrue(utils.str2bool('true')) 25 | 26 | def test_string_to_bool_false(self): 27 | self.assertFalse(utils.str2bool('false')) 28 | 29 | def test_string_to_bool_None(self): 30 | self.assertIsNone(utils.str2bool(None)) 31 | 32 | def test_string_to_dictionary(self): 33 | input_str = 'key1=value1,key2=value2' 34 | expected = {'key1': 'value1', 'key2': 'value2'} 35 | self.assertEqual(expected, utils.str2dict(input_str)) 36 | 37 | def test_none_string_to_dictionary(self): 38 | input_str = '' 39 | expected = {} 40 | self.assertEqual(expected, utils.str2dict(input_str)) 41 | input_str = None 42 | expected = {} 43 | self.assertEqual(expected, utils.str2dict(input_str)) 44 | 45 | def test_get_dict_item_properties(self): 46 | item = {'name': 'test_name', 'id': 'test_id'} 47 | fields = ('name', 'id') 48 | actual = utils.get_item_properties(item=item, fields=fields) 49 | self.assertEqual(('test_name', 'test_id'), actual) 50 | 51 | def test_get_object_item_properties_mixed_case_fields(self): 52 | class Fake(object): 53 | def __init__(self): 54 | self.id = 'test_id' 55 | self.name = 'test_name' 56 | self.test_user = 'test' 57 | 58 | fields = ('name', 'id', 'test user') 59 | mixed_fields = ('test user', 'ID') 60 | item = Fake() 61 | actual = utils.get_item_properties(item, fields, mixed_fields) 62 | self.assertEqual(('test_name', 'test_id', 'test'), actual) 63 | 64 | def test_get_object_item_desired_fields_differ_from_item(self): 65 | class Fake(object): 66 | def __init__(self): 67 | self.id = 'test_id_1' 68 | self.name = 'test_name' 69 | self.test_user = 'test' 70 | 71 | fields = ('name', 'id', 'test user') 72 | item = Fake() 73 | actual = utils.get_item_properties(item, fields) 74 | self.assertNotEqual(('test_name', 'test_id', 'test'), actual) 75 | 76 | def test_get_object_item_desired_fields_is_empty(self): 77 | class Fake(object): 78 | def __init__(self): 79 | self.id = 'test_id_1' 80 | self.name = 'test_name' 81 | self.test_user = 'test' 82 | 83 | fields = [] 84 | item = Fake() 85 | actual = utils.get_item_properties(item, fields) 86 | self.assertEqual((), actual) 87 | 88 | def test_get_object_item_with_formatters(self): 89 | class Fake(object): 90 | def __init__(self): 91 | self.id = 'test_id' 92 | self.name = 'test_name' 93 | self.test_user = 'test' 94 | 95 | class FakeCallable(object): 96 | def __call__(self, *args, **kwargs): 97 | return 'pass' 98 | 99 | fields = ('name', 'id', 'test user', 'is_public') 100 | formatters = {'is_public': FakeCallable()} 101 | item = Fake() 102 | act = utils.get_item_properties(item, fields, formatters=formatters) 103 | self.assertEqual(('test_name', 'test_id', 'test', 'pass'), act) 104 | 105 | 106 | class ImportClassTestCase(testtools.TestCase): 107 | 108 | def test_get_client_class_invalid_version(self): 109 | self.assertRaises( 110 | exceptions.UnsupportedVersion, 111 | utils.get_client_class, 'image', '2', {'image': '2'}) 112 | 113 | 114 | class ContainsKeyValue(object): 115 | """Checks whether a key/value pair is in a dict parameter. 116 | 117 | The ContainsKeyValue class is a helper for mock.assert_*() 118 | method. It enables strict check than the built in mock.ANY 119 | helper, and is the equivalent of the mox.ContainsKeyValue() 120 | function from the legacy mox library 121 | 122 | Example usage could be: 123 | 124 | mock_some_method.assert_called_once_with( 125 | "hello", 126 | ContainsKeyValue('foo', bar), 127 | mock.ANY, 128 | "world", 129 | ContainsKeyValue('hello', world)) 130 | """ 131 | def __init__(self, wantkey, wantvalue): 132 | self.wantkey = wantkey 133 | self.wantvalue = wantvalue 134 | 135 | def __eq__(self, other): 136 | try: 137 | return other[self.wantkey] == self.wantvalue 138 | except (KeyError, TypeError): 139 | return False 140 | 141 | def __ne__(self, other): 142 | try: 143 | return other[self.wantkey] != self.wantvalue 144 | except (KeyError, TypeError): 145 | return True 146 | 147 | def __repr__(self): 148 | return "" 150 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/test_validators.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 NEC Corporation 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import testtools 17 | 18 | from tackerclient.common import exceptions 19 | from tackerclient.common import validators 20 | 21 | 22 | class FakeParsedArgs(object): 23 | pass 24 | 25 | 26 | class ValidatorTest(testtools.TestCase): 27 | 28 | def _test_validate_int(self, attr_val, attr_name='attr1', 29 | min_value=1, max_value=10): 30 | obj = FakeParsedArgs() 31 | setattr(obj, attr_name, attr_val) 32 | ret = validators.validate_int_range(obj, attr_name, 33 | min_value, max_value) 34 | # Come here only if there is no exception. 35 | self.assertIsNone(ret) 36 | 37 | def _test_validate_int_error(self, attr_val, expected_msg, 38 | attr_name='attr1', expected_exc=None, 39 | min_value=1, max_value=10): 40 | if expected_exc is None: 41 | expected_exc = exceptions.CommandError 42 | e = self.assertRaises(expected_exc, 43 | self._test_validate_int, 44 | attr_val, attr_name, min_value, max_value) 45 | self.assertEqual(expected_msg, str(e)) 46 | 47 | def test_validate_int_min_max(self): 48 | self._test_validate_int(1) 49 | self._test_validate_int(10) 50 | self._test_validate_int('1') 51 | self._test_validate_int('10') 52 | self._test_validate_int('0x0a') 53 | 54 | self._test_validate_int_error( 55 | 0, 'attr1 "0" should be an integer [1:10].') 56 | self._test_validate_int_error( 57 | 11, 'attr1 "11" should be an integer [1:10].') 58 | self._test_validate_int_error( 59 | '0x10', 'attr1 "0x10" should be an integer [1:10].') 60 | 61 | def test_validate_int_min_only(self): 62 | self._test_validate_int(1, max_value=None) 63 | self._test_validate_int(10, max_value=None) 64 | self._test_validate_int(11, max_value=None) 65 | self._test_validate_int_error( 66 | 0, 'attr1 "0" should be an integer greater than or equal to 1.', 67 | max_value=None) 68 | 69 | def test_validate_int_max_only(self): 70 | self._test_validate_int(0, min_value=None) 71 | self._test_validate_int(1, min_value=None) 72 | self._test_validate_int(10, min_value=None) 73 | self._test_validate_int_error( 74 | 11, 'attr1 "11" should be an integer smaller than or equal to 10.', 75 | min_value=None) 76 | 77 | def test_validate_int_no_limit(self): 78 | self._test_validate_int(0, min_value=None, max_value=None) 79 | self._test_validate_int(1, min_value=None, max_value=None) 80 | self._test_validate_int(10, min_value=None, max_value=None) 81 | self._test_validate_int(11, min_value=None, max_value=None) 82 | self._test_validate_int_error( 83 | 'abc', 'attr1 "abc" should be an integer.', 84 | min_value=None, max_value=None) 85 | 86 | def _test_validate_subnet(self, attr_val, attr_name='attr1'): 87 | obj = FakeParsedArgs() 88 | setattr(obj, attr_name, attr_val) 89 | ret = validators.validate_ip_subnet(obj, attr_name) 90 | # Come here only if there is no exception. 91 | self.assertIsNone(ret) 92 | 93 | def test_validate_ip_subnet(self): 94 | self._test_validate_subnet('192.168.2.0/24') 95 | self._test_validate_subnet('192.168.2.3/20') 96 | self._test_validate_subnet('192.168.2.1') 97 | 98 | e = self.assertRaises(exceptions.CommandError, 99 | self._test_validate_subnet, 100 | '192.168.2.256') 101 | self.assertEqual('attr1 "192.168.2.256" is not a valid CIDR.', str(e)) 102 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/vm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/tests/unit/vm/__init__.py -------------------------------------------------------------------------------- /tackerclient/tests/unit/vm/samples/vim_config.yaml: -------------------------------------------------------------------------------- 1 | auth_url: 'http://1.2.3.4:5000' 2 | username: 'xyz' 3 | password: '12345' 4 | project_name: 'abc' 5 | project_domain_name: 'prj_domain_name' 6 | user_domain_name: 'user_domain_name' 7 | type: 'openstack' -------------------------------------------------------------------------------- /tackerclient/tests/unit/vm/samples/vim_config_with_false_cert_verify.yaml: -------------------------------------------------------------------------------- 1 | auth_url: 'http://1.2.3.4:5000' 2 | username: 'xyz' 3 | password: '12345' 4 | project_name: 'abc' 5 | project_domain_name: 'prj_domain_name' 6 | user_domain_name: 'user_domain_name' 7 | cert_verify: 'False' 8 | type: 'openstack' -------------------------------------------------------------------------------- /tackerclient/tests/unit/vm/samples/vim_config_without_auth_url.yaml: -------------------------------------------------------------------------------- 1 | username: 'xyz' 2 | password: '12345' 3 | project_name: 'abc' 4 | project_domain_name: 'prj_domain_name' 5 | user_domain_name: 'user_domain_name' 6 | type: 'openstack' 7 | -------------------------------------------------------------------------------- /tackerclient/tests/unit/vm/samples/vim_k8s_bearer_token.yaml: -------------------------------------------------------------------------------- 1 | auth_url: 'https://1.2.3.4:6443' 2 | bearer_token: 'xyz' 3 | ssl_ca_cert: None 4 | project_name: 'default' 5 | type: 'kubernetes' -------------------------------------------------------------------------------- /tackerclient/tests/unit/vm/samples/vim_k8s_bearer_token_without_auth_url.yaml: -------------------------------------------------------------------------------- 1 | bearer_token: 'xyz' 2 | ssl_ca_cert: None 3 | project_name: 'default' 4 | type: 'kubernetes' -------------------------------------------------------------------------------- /tackerclient/tests/unit/vm/samples/vim_k8s_config.yaml: -------------------------------------------------------------------------------- 1 | auth_url: 'https://1.2.3.4:6443' 2 | username: 'xyz' 3 | password: '12345' 4 | ssl_ca_cert: 'abcxyz' 5 | project_name: 'default' 6 | type: 'kubernetes' -------------------------------------------------------------------------------- /tackerclient/tests/unit/vm/samples/vim_k8s_config_without_auth_url.yaml: -------------------------------------------------------------------------------- 1 | username: 'xyz' 2 | password: '12345' 3 | ssl_ca_cert: 'abcxyz' 4 | project_name: 'default' 5 | type: 'kubernetes' -------------------------------------------------------------------------------- /tackerclient/v1_0/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/python-tackerclient/c2bdc92c2ee4568279beae91f41a564f9372eb5c/tackerclient/v1_0/__init__.py -------------------------------------------------------------------------------- /tackerclient/version.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. 2 | # All Rights Reserved 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import pbr.version 17 | 18 | 19 | __version__ = pbr.version.VersionInfo('python-tackerclient').version_string() 20 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | # The order of packages is significant, because pip processes them in the order 2 | # of appearance. Changing the order has an impact on the overall integration 3 | # process, which may cause wedges in the gate later. 4 | 5 | hacking>=7.0.0,<7.1.0 # Apache-2.0 6 | coverage!=4.4,>=4.0 # Apache-2.0 7 | ddt>=1.0.1 # MIT 8 | fixtures>=3.0.0 # Apache-2.0/BSD 9 | python-subunit>=1.0.0 # Apache-2.0/BSD 10 | requests-mock>=1.2.0 # Apache-2.0 11 | stestr>=2.0.0 # Apache-2.0 12 | testtools>=2.2.0 # MIT 13 | -------------------------------------------------------------------------------- /tools/tacker.bash_completion: -------------------------------------------------------------------------------- 1 | _tacker_opts="" # lazy init 2 | _tacker_flags="" # lazy init 3 | _tacker_opts_exp="" # lazy init 4 | _tacker() 5 | { 6 | local cur prev nbc cflags 7 | COMPREPLY=() 8 | cur="${COMP_WORDS[COMP_CWORD]}" 9 | prev="${COMP_WORDS[COMP_CWORD-1]}" 10 | 11 | if [ "x$_tacker_opts" == "x" ] ; then 12 | nbc="`tacker bash-completion`" 13 | _tacker_opts="`echo "$nbc" | sed -e "s/--[a-z0-9_-]*//g" -e "s/\s\s*/ /g"`" 14 | _tacker_flags="`echo " $nbc" | sed -e "s/ [^-][^-][a-z0-9_-]*//g" -e "s/\s\s*/ /g"`" 15 | _tacker_opts_exp="`echo "$_tacker_opts" | sed -e "s/\s/|/g"`" 16 | fi 17 | 18 | if [[ " ${COMP_WORDS[@]} " =~ " "($_tacker_opts_exp)" " && "$prev" != "help" ]] ; then 19 | COMPLETION_CACHE=~/.tackerclient/*/*-cache 20 | cflags="$_tacker_flags "$(cat $COMPLETION_CACHE 2> /dev/null | tr '\n' ' ') 21 | COMPREPLY=($(compgen -W "${cflags}" -- ${cur})) 22 | else 23 | COMPREPLY=($(compgen -W "${_tacker_opts}" -- ${cur})) 24 | fi 25 | return 0 26 | } 27 | complete -F _tacker tacker 28 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py39,py38,py36,pep8,docs 3 | minversion = 3.18.0 4 | ignore_basepython_conflict = True 5 | 6 | [testenv] 7 | basepython = python3 8 | setenv = VIRTUAL_ENV={envdir} 9 | LANG=en_US.UTF-8 10 | LANGUAGE=en_US:en 11 | LC_ALL=C 12 | usedevelop = True 13 | deps = 14 | -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} 15 | -r{toxinidir}/requirements.txt 16 | -r{toxinidir}/test-requirements.txt 17 | commands = stestr run --slowest {posargs} 18 | 19 | [testenv:pep8] 20 | commands = flake8 21 | distribute = false 22 | 23 | [testenv:venv] 24 | commands = {posargs} 25 | 26 | [testenv:docs] 27 | deps = -r{toxinidir}/doc/requirements.txt 28 | commands = sphinx-build -W -b html doc/source doc/build/html 29 | 30 | [testenv:releasenotes] 31 | deps = 32 | -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} 33 | -r{toxinidir}/doc/requirements.txt 34 | commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html 35 | 36 | [testenv:cover] 37 | setenv = 38 | PYTHON=coverage run --source tackerclient --parallel-mode 39 | commands = 40 | stestr run {posargs} 41 | coverage combine 42 | coverage html -d cover 43 | coverage xml -o cover/coverage.xml 44 | 45 | [flake8] 46 | # E125 continuation line does not distinguish itself from next logical line 47 | # W504 line break after binary operator 48 | ignore = E125,W504 49 | show-source = true 50 | exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,tools 51 | # F821 undefined name 'unicode' 52 | # if isinstance(config, str) or isinstance(config, unicode): 53 | builtins = unicode 54 | --------------------------------------------------------------------------------