diff --git a/.fence-agents.metadata b/.fence-agents.metadata index dbe08d2..8cb773a 100644 --- a/.fence-agents.metadata +++ b/.fence-agents.metadata @@ -2,7 +2,6 @@ e1b766b2b1601fde67b3b19ed2f13b9746bb1cca SOURCES/MarkupSafe-2.0.1.tar.gz e1fb5dc6f95a85e7d1f93c6701b331201e8b5479 SOURCES/PyJWT-2.1.0-py3-none-any.whl 53fc16036940089ceadd4127381e40fd6106a7ed SOURCES/PyYAML-5.1.tar.gz -a8c40a3ae9d4c159382a58db3153d83e5521c51e SOURCES/PyYAML-6.0.tar.gz b53cba68215f389dffaa51ee2afe10c943278646 SOURCES/adal-1.2.7-py2.py3-none-any.whl bda476965c380701795849179ed91e9d8134ec7c SOURCES/aliyun-python-sdk-core-2.11.5.tar.gz 2a3e6ee5713a3cfb47e63a739cc9a05580d95dd6 SOURCES/aliyun_python_sdk_ecs-4.24.7-py2.py3-none-any.whl @@ -25,11 +24,9 @@ b13e22d55867e2ca5f92e5289cfdc21ba6e343aa SOURCES/certifi-2021.10.8.tar.gz 96faab7de7e9a71b37f22adb64daf2898e967e3e SOURCES/chardet-3.0.4-py2.py3-none-any.whl e9eb83c71c09b3c8249bd7d6d2619b65fff03874 SOURCES/chardet-4.0.0-py2.py3-none-any.whl 865df92e66e5dc7b940144cbad8115c07dc8784f SOURCES/charset-normalizer-2.0.7.tar.gz -9fa96037a1a985fe7dda81c0e1e35ae015163d88 SOURCES/charset_normalizer-2.0.4-py3-none-any.whl a8ee91adf4644bbdccfc73ead88f4cd0df7e3552 SOURCES/colorama-0.3.3.tar.gz 444d5ea320f95cd6205535a1be2805598847191b SOURCES/colorama-0.4.3-py2.py3-none-any.whl 536a57d70d505e4de8595650603d7e2ecc58b34b SOURCES/cryptography-3.3.2-cp36-abi3-manylinux2010_x86_64.whl -dfabded3494bffe6965b1bf3d37383736e642bdb SOURCES/debtcollector-2.2.0-py3-none-any.whl 4b50bebad4c5036c030a78cbb869d039bc91c4ec SOURCES/distro-1.5.0-py2.py3-none-any.whl aafeddc912b74557754b2aaece3f1364be8e9f6a SOURCES/docutils-0.15.2-py3-none-any.whl 1ec823f807b73a377cdd47d12e2e34f046bfc889 SOURCES/fence-agents-4.10.0.tar.gz @@ -41,33 +38,19 @@ ac160113ba8b78b0688edda9f9a088c0b4b5ded2 SOURCES/google_api_core-1.30.0-py2.py3- dc553afa7a3f23b92ee9ecd27d0b15153c0e9f75 SOURCES/googleapis_common_protos-1.53.0-py2.py3-none-any.whl 74ec77d2e2ef6b2ef8503e6e398faa6f3ba298ae SOURCES/httplib2-0.19.1-py3-none-any.whl 999b6718b4d789d8ca0d2ddf7c07826154291825 SOURCES/idna-2.10-py2.py3-none-any.whl -e3a19aca36f6631ba9e33e66b855835776e8e120 SOURCES/idna-3.2-py3-none-any.whl 08c0449533fc94462f78652dea209099754d9ee4 SOURCES/idna-3.3.tar.gz -8672ed298c51abba24fdf5298ddeef7b16027071 SOURCES/iso8601-0.1.16-py2.py3-none-any.whl 240cc4206740fafacb74bbf0d0c4ff70e41c8a85 SOURCES/isodate-0.6.0-py2.py3-none-any.whl 68904717c48e95adb47d815178fff8d80f39b2ab SOURCES/jmespath-0.7.1-py2.py3-none-any.whl -22a38dbc79cc3cbe53c2bf306ad22a472be1a6f4 SOURCES/keystoneauth1-4.3.1-py3-none-any.whl d06a9547b1a87e9c51b0a7c708189d993f2e3d89 SOURCES/kubernetes-12.0.1.tar.gz -194b341fe37fe6ce992c637a728484e3cee47394 SOURCES/msgpack-1.0.2.tar.gz ba59fbd147307e7ef92a1fad259e7dc0b07e79e0 SOURCES/msrest-0.6.21-py2.py3-none-any.whl 3d65a50b68e3aa506b6af42be485ed2710afa9da SOURCES/msrestazure-0.6.4-py2.py3-none-any.whl -ee77c30d5350378e9ca9932b724d1a26c9cc164b SOURCES/netaddr-0.8.0-py2.py3-none-any.whl -c1dd2b481a0101eb518bf47bdf40ea53ab61ca62 SOURCES/netifaces-0.11.0.tar.gz 0b5ba4c47bdd7ff17ca4954349d7213a95d03f25 SOURCES/oauthlib-3.1.1-py2.py3-none-any.whl f6efa66f6106b069b5c0e0cf8cc677e4e96c91ca SOURCES/oauthlib-3.1.1.tar.gz 570d69d8c108ebb8aee562389d13b07dfb61ce25 SOURCES/openshift-0.12.1.tar.gz -2b0aea8c7985b474f0719b916a1b6475caedf42f SOURCES/os_service_types-1.7.0-py2.py3-none-any.whl -e26e191810fd455958aa3fcf7c7447180c14de8d SOURCES/oslo.config-8.7.1-py3-none-any.whl -7375d2b1c5d3b13d5637a00b9514104069bca329 SOURCES/oslo.i18n-5.0.1-py3-none-any.whl -8a4aab8b645772fa6132df1ce23267b2fae356d3 SOURCES/oslo.serialization-4.2.0-py3-none-any.whl -b302350fda92e8b96a402fbb4cdf639f06192b62 SOURCES/oslo.utils-4.10.0-py3-none-any.whl 2b10cb7681bc678ba4ff3be524b28d783e4095ce SOURCES/packaging-20.9-py2.py3-none-any.whl -f712c7731d0d65cfc8fc7c61afeeeeca4b84b549 SOURCES/packaging-21.0-py3-none-any.whl bccbc1bf76a9db46998eb8e1ffa2f2a2baf9237a SOURCES/packaging-21.2-py3-none-any.whl -d3d07b885ca4d10994a30682106e37785e6e780c SOURCES/pbr-5.6.0-py2.py3-none-any.whl 0c3fc83ca045abeec9ce82bb7ee3e77f0390bca4 SOURCES/pexpect-4.8.0-py2.py3-none-any.whl 18659a0dea5600df33eab90dec1b597e2437aebd SOURCES/poetry-core-1.0.7.tar.gz -5ad34ad3dbfaf6d4e72860287043120c641e4524 SOURCES/prettytable-2.2.0-py3-none-any.whl b09c4655a4c8bd24c54a078e960750ec9e8688d6 SOURCES/prompt_toolkit-2.0.10-py3-none-any.whl 5a90b79a9630873c7f2db79544c46146bb6af5e8 SOURCES/protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl 0827aaa6fdc3dc4256e06fa1c3991fb4ed20a693 SOURCES/ptyprocess-0.7.0-py2.py3-none-any.whl @@ -90,15 +73,11 @@ e58f6fa56f1baf766ba147dbc9fbfc67fa92e234 SOURCES/pyroute2.ethtool-0.6.4.tar.gz c2ba10c775b7a52a4b57cac4d4110a0c0f812a82 SOURCES/python-dateutil-2.8.2.tar.gz 1dc2fa004aa6517f1620e55d8a7b8e68a9cf2a47 SOURCES/python-string-utils-1.0.0.tar.gz 3005ff67df93ee276fb8631e17c677df852254ad SOURCES/python_dateutil-2.8.1-py2.py3-none-any.whl -e10df4212f19d34774bb329e8b497dafa4d099d5 SOURCES/python_keystoneclient-4.2.0-py3-none-any.whl -2c61c4407646813e5e5dd6f09586704efca371f0 SOURCES/python_novaclient-17.5.0-py3-none-any.whl b97c6966fb8fd273f0bc8533cf0dee4978b9f373 SOURCES/pytz-2021.1-py2.py3-none-any.whl b1009d9fd6acadc64e1a3cecb6f0083fe047e753 SOURCES/requests-2.25.1-py2.py3-none-any.whl -d20e2df000dd43249c3a9eed041f08a812a93423 SOURCES/requests-2.26.0-py2.py3-none-any.whl 8c7a89d183d3e9b70bf91ba5b75eccf7111b9d8d SOURCES/requests-2.26.0.tar.gz f139aed770519b6a095b8fdc888d03955cbe9d8e SOURCES/requests-oauthlib-1.3.0.tar.gz 25d5667d7a61586f5ddaac7e08cc3053db3d8661 SOURCES/requests_oauthlib-1.3.0-py2.py3-none-any.whl -b8e2041ff9ad37dba2f78e4b59b57cbed5f1b8ff SOURCES/rfc3986-1.5.0-py2.py3-none-any.whl c0d5be2edf538122d35fe06c29d2d7a5f22f3117 SOURCES/rsa-4.7.2-py3-none-any.whl e8a53067e03fe1b6682fd99a40a7359396a06daa SOURCES/rsa-4.7.2.tar.gz abf532a0cc31ea224e3895f60025e7466b16d7ae SOURCES/ruamel.yaml-0.15.100.tar.gz @@ -110,14 +89,11 @@ d5354718cb8c9330d3abc27445467ce8a5ed9d70 SOURCES/setuptools-58.3.0.tar.gz a4f02fddae697614e356cadfddb6241cc7737f38 SOURCES/setuptools_scm-6.3.2.tar.gz 79e6f2e4f9e24898f1896df379871b9c9922f147 SOURCES/six-1.16.0-py2.py3-none-any.whl 06fa0bb50f2a4e2917fd14c21e9d2d5508ce0163 SOURCES/six-1.16.0.tar.gz -c612ea4b006feec1444ac61c233632f7e4852380 SOURCES/stevedore-3.4.0-py3-none-any.whl 47a980b20875d1a1714e921552b5bb0eda190f37 SOURCES/suds_community-0.8.5-py3-none-any.whl b42b7960047441db7dc021cc20e14279bd836f8d SOURCES/tomli-1.0.1.tar.gz 83be56610e5f824bb05ff7a5618d6d4df9b6cc08 SOURCES/uritemplate-3.0.1-py2.py3-none-any.whl 206b17697417cbf5fc55f1e39c7ceb2197fe3e63 SOURCES/urllib3-1.26.6-py2.py3-none-any.whl eb35c3fd8b0867ae988a15917d6b80e8bdf60222 SOURCES/urllib3-1.26.7.tar.gz 7126323614cada181bc8b06436e80ef372ff8656 SOURCES/wcwidth-0.1.9-py2.py3-none-any.whl -6cbb5d6384f6d2c8667fb3c5710ecf90dbf9e7fc SOURCES/wcwidth-0.2.5-py2.py3-none-any.whl 540f083782c584989c1a0f69ffd69ba7aae07db6 SOURCES/websocket-client-1.2.1.tar.gz b6c48d8714e043524be7a869d1db0adcd8441cd4 SOURCES/wheel-0.37.0-py2.py3-none-any.whl -6c18d34144c6faba208509b8091d35acc9842081 SOURCES/wrapt-1.12.1.tar.gz diff --git a/.gitignore b/.gitignore index 7a5fd7b..5857b7c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ SOURCES/Jinja2-3.0.2.tar.gz SOURCES/MarkupSafe-2.0.1.tar.gz SOURCES/PyJWT-2.1.0-py3-none-any.whl SOURCES/PyYAML-5.1.tar.gz -SOURCES/PyYAML-6.0.tar.gz SOURCES/adal-1.2.7-py2.py3-none-any.whl SOURCES/aliyun-python-sdk-core-2.11.5.tar.gz SOURCES/aliyun_python_sdk_ecs-4.24.7-py2.py3-none-any.whl @@ -25,11 +24,9 @@ SOURCES/cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl SOURCES/chardet-3.0.4-py2.py3-none-any.whl SOURCES/chardet-4.0.0-py2.py3-none-any.whl SOURCES/charset-normalizer-2.0.7.tar.gz -SOURCES/charset_normalizer-2.0.4-py3-none-any.whl SOURCES/colorama-0.3.3.tar.gz SOURCES/colorama-0.4.3-py2.py3-none-any.whl SOURCES/cryptography-3.3.2-cp36-abi3-manylinux2010_x86_64.whl -SOURCES/debtcollector-2.2.0-py3-none-any.whl SOURCES/distro-1.5.0-py2.py3-none-any.whl SOURCES/docutils-0.15.2-py3-none-any.whl SOURCES/fence-agents-4.10.0.tar.gz @@ -41,33 +38,19 @@ SOURCES/google_auth_httplib2-0.1.0-py2.py3-none-any.whl SOURCES/googleapis_common_protos-1.53.0-py2.py3-none-any.whl SOURCES/httplib2-0.19.1-py3-none-any.whl SOURCES/idna-2.10-py2.py3-none-any.whl -SOURCES/idna-3.2-py3-none-any.whl SOURCES/idna-3.3.tar.gz -SOURCES/iso8601-0.1.16-py2.py3-none-any.whl SOURCES/isodate-0.6.0-py2.py3-none-any.whl SOURCES/jmespath-0.7.1-py2.py3-none-any.whl -SOURCES/keystoneauth1-4.3.1-py3-none-any.whl SOURCES/kubernetes-12.0.1.tar.gz -SOURCES/msgpack-1.0.2.tar.gz SOURCES/msrest-0.6.21-py2.py3-none-any.whl SOURCES/msrestazure-0.6.4-py2.py3-none-any.whl -SOURCES/netaddr-0.8.0-py2.py3-none-any.whl -SOURCES/netifaces-0.11.0.tar.gz SOURCES/oauthlib-3.1.1-py2.py3-none-any.whl SOURCES/oauthlib-3.1.1.tar.gz SOURCES/openshift-0.12.1.tar.gz -SOURCES/os_service_types-1.7.0-py2.py3-none-any.whl -SOURCES/oslo.config-8.7.1-py3-none-any.whl -SOURCES/oslo.i18n-5.0.1-py3-none-any.whl -SOURCES/oslo.serialization-4.2.0-py3-none-any.whl -SOURCES/oslo.utils-4.10.0-py3-none-any.whl SOURCES/packaging-20.9-py2.py3-none-any.whl -SOURCES/packaging-21.0-py3-none-any.whl SOURCES/packaging-21.2-py3-none-any.whl -SOURCES/pbr-5.6.0-py2.py3-none-any.whl SOURCES/pexpect-4.8.0-py2.py3-none-any.whl SOURCES/poetry-core-1.0.7.tar.gz -SOURCES/prettytable-2.2.0-py3-none-any.whl SOURCES/prompt_toolkit-2.0.10-py3-none-any.whl SOURCES/protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl SOURCES/ptyprocess-0.7.0-py2.py3-none-any.whl @@ -90,15 +73,11 @@ SOURCES/pyroute2.nslink-0.6.4.tar.gz SOURCES/python-dateutil-2.8.2.tar.gz SOURCES/python-string-utils-1.0.0.tar.gz SOURCES/python_dateutil-2.8.1-py2.py3-none-any.whl -SOURCES/python_keystoneclient-4.2.0-py3-none-any.whl -SOURCES/python_novaclient-17.5.0-py3-none-any.whl SOURCES/pytz-2021.1-py2.py3-none-any.whl SOURCES/requests-2.25.1-py2.py3-none-any.whl -SOURCES/requests-2.26.0-py2.py3-none-any.whl SOURCES/requests-2.26.0.tar.gz SOURCES/requests-oauthlib-1.3.0.tar.gz SOURCES/requests_oauthlib-1.3.0-py2.py3-none-any.whl -SOURCES/rfc3986-1.5.0-py2.py3-none-any.whl SOURCES/rsa-4.7.2-py3-none-any.whl SOURCES/rsa-4.7.2.tar.gz SOURCES/ruamel.yaml-0.15.100.tar.gz @@ -110,14 +89,11 @@ SOURCES/setuptools-58.3.0.tar.gz SOURCES/setuptools_scm-6.3.2.tar.gz SOURCES/six-1.16.0-py2.py3-none-any.whl SOURCES/six-1.16.0.tar.gz -SOURCES/stevedore-3.4.0-py3-none-any.whl SOURCES/suds_community-0.8.5-py3-none-any.whl SOURCES/tomli-1.0.1.tar.gz SOURCES/uritemplate-3.0.1-py2.py3-none-any.whl SOURCES/urllib3-1.26.6-py2.py3-none-any.whl SOURCES/urllib3-1.26.7.tar.gz SOURCES/wcwidth-0.1.9-py2.py3-none-any.whl -SOURCES/wcwidth-0.2.5-py2.py3-none-any.whl SOURCES/websocket-client-1.2.1.tar.gz SOURCES/wheel-0.37.0-py2.py3-none-any.whl -SOURCES/wrapt-1.12.1.tar.gz diff --git a/SOURCES/bz2010652-fence_azure_arm-fix-sovereign-cloud-msi-support.patch b/SOURCES/bz2010652-fence_azure_arm-fix-sovereign-cloud-msi-support.patch new file mode 100644 index 0000000..4077484 --- /dev/null +++ b/SOURCES/bz2010652-fence_azure_arm-fix-sovereign-cloud-msi-support.patch @@ -0,0 +1,139 @@ +From e339f304d4423a0e661d915f72ba88553b21d74a Mon Sep 17 00:00:00 2001 +From: MSSedusch +Date: Tue, 28 Sep 2021 12:23:37 +0000 +Subject: [PATCH 1/2] add support for sovereign clouds and MSI + +--- + lib/azure_fence.py.py | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/lib/azure_fence.py.py b/lib/azure_fence.py.py +index 1f38bd4ea..75b63fdad 100644 +--- a/lib/azure_fence.py.py ++++ b/lib/azure_fence.py.py +@@ -286,11 +286,11 @@ def get_azure_credentials(config): + credentials = None + cloud_environment = get_azure_cloud_environment(config) + if config.UseMSI and cloud_environment: +- from msrestazure.azure_active_directory import MSIAuthentication +- credentials = MSIAuthentication(cloud_environment=cloud_environment) ++ from azure.identity import ManagedIdentityCredential ++ credentials = ManagedIdentityCredential(cloud_environment=cloud_environment) + elif config.UseMSI: +- from msrestazure.azure_active_directory import MSIAuthentication +- credentials = MSIAuthentication() ++ from azure.identity import ManagedIdentityCredential ++ credentials = ManagedIdentityCredential() + elif cloud_environment: + try: + # try to use new libraries ClientSecretCredential (azure.identity, based on azure.core) +@@ -340,7 +340,8 @@ def get_azure_compute_client(config): + compute_client = ComputeManagementClient( + credentials, + config.SubscriptionId, +- base_url=cloud_environment.endpoints.resource_manager ++ base_url=cloud_environment.endpoints.resource_manager, ++ credential_scopes=[cloud_environment.endpoints.resource_manager + "/.default"] + ) + else: + compute_client = ComputeManagementClient( +@@ -359,7 +360,8 @@ def get_azure_network_client(config): + network_client = NetworkManagementClient( + credentials, + config.SubscriptionId, +- base_url=cloud_environment.endpoints.resource_manager ++ base_url=cloud_environment.endpoints.resource_manager, ++ credential_scopes=[cloud_environment.endpoints.resource_manager + "/.default"] + ) + else: + network_client = NetworkManagementClient( + +From f08f02a7561e78dd9c95c66ccdcf6246c5ee7d6a Mon Sep 17 00:00:00 2001 +From: MSSedusch +Date: Fri, 1 Oct 2021 15:28:39 +0000 +Subject: [PATCH 2/2] compatiblity fix + +--- + lib/azure_fence.py.py | 54 ++++++++++++++++++++++++++++++------------- + 1 file changed, 38 insertions(+), 16 deletions(-) + +diff --git a/lib/azure_fence.py.py b/lib/azure_fence.py.py +index 75b63fdad..5ca71eb42 100644 +--- a/lib/azure_fence.py.py ++++ b/lib/azure_fence.py.py +@@ -286,11 +286,19 @@ def get_azure_credentials(config): + credentials = None + cloud_environment = get_azure_cloud_environment(config) + if config.UseMSI and cloud_environment: +- from azure.identity import ManagedIdentityCredential +- credentials = ManagedIdentityCredential(cloud_environment=cloud_environment) ++ try: ++ from azure.identity import ManagedIdentityCredential ++ credentials = ManagedIdentityCredential(cloud_environment=cloud_environment) ++ except ImportError: ++ from msrestazure.azure_active_directory import MSIAuthentication ++ credentials = MSIAuthentication(cloud_environment=cloud_environment) + elif config.UseMSI: +- from azure.identity import ManagedIdentityCredential +- credentials = ManagedIdentityCredential() ++ try: ++ from azure.identity import ManagedIdentityCredential ++ credentials = ManagedIdentityCredential() ++ except ImportError: ++ from msrestazure.azure_active_directory import MSIAuthentication ++ credentials = MSIAuthentication() + elif cloud_environment: + try: + # try to use new libraries ClientSecretCredential (azure.identity, based on azure.core) +@@ -337,12 +345,19 @@ def get_azure_compute_client(config): + credentials = get_azure_credentials(config) + + if cloud_environment: +- compute_client = ComputeManagementClient( +- credentials, +- config.SubscriptionId, +- base_url=cloud_environment.endpoints.resource_manager, +- credential_scopes=[cloud_environment.endpoints.resource_manager + "/.default"] +- ) ++ try: ++ compute_client = ComputeManagementClient( ++ credentials, ++ config.SubscriptionId, ++ base_url=cloud_environment.endpoints.resource_manager, ++ credential_scopes=[cloud_environment.endpoints.resource_manager + "/.default"] ++ ) ++ except TypeError: ++ compute_client = ComputeManagementClient( ++ credentials, ++ config.SubscriptionId, ++ base_url=cloud_environment.endpoints.resource_manager ++ ) + else: + compute_client = ComputeManagementClient( + credentials, +@@ -357,12 +372,19 @@ def get_azure_network_client(config): + credentials = get_azure_credentials(config) + + if cloud_environment: +- network_client = NetworkManagementClient( +- credentials, +- config.SubscriptionId, +- base_url=cloud_environment.endpoints.resource_manager, +- credential_scopes=[cloud_environment.endpoints.resource_manager + "/.default"] +- ) ++ try: ++ network_client = NetworkManagementClient( ++ credentials, ++ config.SubscriptionId, ++ base_url=cloud_environment.endpoints.resource_manager, ++ credential_scopes=[cloud_environment.endpoints.resource_manager + "/.default"] ++ ) ++ except TypeError: ++ network_client = NetworkManagementClient( ++ credentials, ++ config.SubscriptionId, ++ base_url=cloud_environment.endpoints.resource_manager ++ ) + else: + network_client = NetworkManagementClient( + credentials, diff --git a/SOURCES/bz2041933-bz2041935-3-fencing-source_env-dont-process-empty-lines.patch b/SOURCES/bz2041933-bz2041935-3-fencing-source_env-dont-process-empty-lines.patch new file mode 100644 index 0000000..8803895 --- /dev/null +++ b/SOURCES/bz2041933-bz2041935-3-fencing-source_env-dont-process-empty-lines.patch @@ -0,0 +1,22 @@ +From fbca33a536413565108374dd4ed3237b6f7896bd Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 15 Aug 2022 10:40:19 +0200 +Subject: [PATCH] fencing: source_env(): dont process empty lines + +--- + lib/fencing.py.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/fencing.py.py b/lib/fencing.py.py +index fc3679e33..940bd01d1 100644 +--- a/lib/fencing.py.py ++++ b/lib/fencing.py.py +@@ -1264,7 +1264,7 @@ def source_env(env_file): + executable="/bin/sh") + # replace env + os.environ.clear() +- os.environ.update(line.partition('=')[::2] for line in output.decode("utf-8").split('\0')) ++ os.environ.update(line.partition('=')[::2] for line in output.decode("utf-8").split('\0') if not re.match("^\s*$", line)) + + # Convert array of format [[key1, value1], [key2, value2], ... [keyN, valueN]] to dict, where key is + # in format a.b.c.d...z and returned dict has key only z diff --git a/SOURCES/bz2065114-fence_lpar-refactor.patch b/SOURCES/bz2065114-fence_lpar-refactor.patch new file mode 100644 index 0000000..599a22c --- /dev/null +++ b/SOURCES/bz2065114-fence_lpar-refactor.patch @@ -0,0 +1,65 @@ +From e3dff8570b70f0c19eca84cf02f0aadd68e16599 Mon Sep 17 00:00:00 2001 +From: Thomas Renninger +Date: Fri, 25 Feb 2022 14:05:42 +0100 +Subject: [PATCH] fence_lpar: fix missing import logging, use fail_usage + +and slightly re-factor code to avoid duplicate code lines. +Should be cleanup only, no functional change. +--- + agents/lpar/fence_lpar.py | 39 ++++++++++++++++++--------------------- + 1 file changed, 18 insertions(+), 21 deletions(-) + +diff --git a/agents/lpar/fence_lpar.py b/agents/lpar/fence_lpar.py +index ad18c6191..2046b0e4e 100644 +--- a/agents/lpar/fence_lpar.py ++++ b/agents/lpar/fence_lpar.py +@@ -28,31 +28,28 @@ def _normalize_status(status): + + def get_power_status(conn, options): + if options["--hmc-version"] == "3": +- conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n") +- +- # First line (command) may cause parsing issues if long +- conn.readline() +- conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) +- +- try: +- status = re.compile("^" + options["--plug"] + ",(.*?),.*$", +- re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) +- except AttributeError as e: +- logging.error("Failed: {}".format(str(e))) +- fail(EC_STATUS_HMC) ++ command = "lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n" + elif options["--hmc-version"] in ["4", "IVM"]: +- conn.send("lssyscfg -r lpar -m "+ options["--managed"] + +- " --filter 'lpar_names=" + options["--plug"] + "'\n") ++ command = "lssyscfg -r lpar -m "+ options["--managed"] + \ ++ " --filter 'lpar_names=" + options["--plug"] + "'\n" ++ else: ++ # Bad HMC Version cannot be reached ++ fail(EC_STATUS_HMC) + +- # First line (command) may cause parsing issues if long +- conn.readline() +- conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) ++ conn.send(command) ++ # First line (command) may cause parsing issues if long ++ conn.readline() ++ conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +- try: ++ try: ++ if options["--hmc-version"] == "3": ++ status = re.compile("^" + options["--plug"] + ",(.*?),.*$", ++ re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) ++ elif options["--hmc-version"] in ["4", "IVM"]: + status = re.compile(",state=(.*?),", re.IGNORECASE).search(conn.before).group(1) +- except AttributeError as e: +- logging.error("Failed: {}".format(str(e))) +- fail(EC_STATUS_HMC) ++ except AttributeError as e: ++ fail_usage("Command on HMC failed: {}\n{}".format(command, str(e)), False) ++ fail(EC_STATUS_HMC) + + return _normalize_status(status) + diff --git a/SOURCES/bz2072420-1-all-agents-unify-ssl-parameters.patch b/SOURCES/bz2072420-1-all-agents-unify-ssl-parameters.patch new file mode 100644 index 0000000..6f8f0af --- /dev/null +++ b/SOURCES/bz2072420-1-all-agents-unify-ssl-parameters.patch @@ -0,0 +1,291 @@ +From 999f2f8b4dc7d258679daf8c3f13d9b317ff4435 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 7 Apr 2022 13:11:12 +0200 +Subject: [PATCH] all agents: unify ssl parameters to avoid having to use --ssl + when using --ssl-secure/--ssl-insecure for some agents + +THIS MIGHT BREAK SETUPS USING fence_docker or fence_pve! +--- + agents/cisco_ucs/fence_cisco_ucs.py | 9 +++++---- + agents/docker/fence_docker.py | 9 ++++++--- + agents/ibmz/fence_ibmz.py | 4 ++-- + agents/rhevm/fence_rhevm.py | 8 ++++---- + agents/skalar/fence_skalar.py | 2 +- + agents/vmware_rest/fence_vmware_rest.py | 8 ++++---- + agents/vmware_soap/fence_vmware_soap.py | 2 +- + agents/vmware_vcloud/fence_vmware_vcloud.py | 4 ++-- + agents/zvm/fence_zvmip.py | 8 +++++--- + lib/fencing.py.py | 6 ++++++ + tests/data/metadata/fence_docker.xml | 4 ++-- + 13 files changed, 64 insertions(+), 31 deletions(-) + +diff --git a/agents/cisco_ucs/fence_cisco_ucs.py b/agents/cisco_ucs/fence_cisco_ucs.py +index 2280dbbc7..b85379a73 100644 +--- a/agents/cisco_ucs/fence_cisco_ucs.py ++++ b/agents/cisco_ucs/fence_cisco_ucs.py +@@ -99,7 +99,7 @@ def get_list(conn, options): + + def send_command(opt, command, timeout): + ## setup correct URL +- if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt: ++ if "--ssl-secure" in opt or "--ssl-insecure" in opt: + url = "https:" + else: + url = "http:" +@@ -114,13 +114,14 @@ def send_command(opt, command, timeout): + conn.setopt(pycurl.POSTFIELDS, command.encode("ascii")) + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + conn.setopt(pycurl.TIMEOUT, timeout) +- if "--ssl" in opt or "--ssl-secure" in opt: ++ ++ if "--ssl-secure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) +- +- if "--ssl-insecure" in opt: ++ elif "--ssl-insecure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) ++ + conn.perform() + result = web_buffer.getvalue().decode() + +diff --git a/agents/docker/fence_docker.py b/agents/docker/fence_docker.py +index fef87da86..004402518 100644 +--- a/agents/docker/fence_docker.py ++++ b/agents/docker/fence_docker.py +@@ -43,7 +43,7 @@ def get_list(conn, options): + + + def send_cmd(options, cmd, post = False): +- url = "http%s://%s:%s/v%s/%s" % ("s" if "--ssl" in options else "", options["--ip"], options["--ipport"], options["--api-version"], cmd) ++ url = "http%s://%s:%s/v%s/%s" % ("s" if "--ssl-secure" in options or "--ssl-insecure" in options else "", options["--ip"], options["--ipport"], options["--api-version"], cmd) + conn = pycurl.Curl() + output_buffer = io.BytesIO() + if logging.getLogger().getEffectiveLevel() < logging.WARNING: +@@ -55,7 +55,8 @@ def send_cmd(options, cmd, post = False): + conn.setopt(pycurl.POSTFIELDSIZE, 0) + conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write) + conn.setopt(pycurl.TIMEOUT, int(options["--shell-timeout"])) +- if "--ssl" in options: ++ ++ if "--ssl-secure" in options: + if not (set(("--tlscert", "--tlskey", "--tlscacert")) <= set(options)): + fail_usage("Failed. If --ssl option is used, You have to also \ + specify: --tlscert, --tlskey and --tlscacert") +@@ -63,7 +64,7 @@ def send_cmd(options, cmd, post = False): + conn.setopt(pycurl.SSLCERT, options["--tlscert"]) + conn.setopt(pycurl.SSLKEY, options["--tlskey"]) + conn.setopt(pycurl.CAINFO, options["--tlscacert"]) +- else: ++ elif "--ssl-insecure" in options: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + +@@ -136,6 +137,8 @@ def main(): + + device_opt = ["ipaddr", "no_password", "no_login", "port", "method", "web", "tlscert", "tlskey", "tlscacert", "ssl", "api_version"] + ++ all_opt["ssl"]["default"] = "1" ++ + options = check_input(device_opt, process_input(device_opt)) + + docs = { } +diff --git a/agents/ibmz/fence_ibmz.py b/agents/ibmz/fence_ibmz.py +index 47408ccf4..d477adeb9 100644 +--- a/agents/ibmz/fence_ibmz.py ++++ b/agents/ibmz/fence_ibmz.py +@@ -534,7 +534,7 @@ def main(): + requests_log.propagate = True + if "--verbose" in options: + requests_log.setLevel(logging.DEBUG) +- if "--ssl-secure" not in options: ++ if "--ssl-insecure" in options: + urllib3.disable_warnings( + category=urllib3.exceptions.InsecureRequestWarning) + +@@ -548,7 +548,7 @@ def main(): + 'connect_timeout': int(options['--connect-timeout']), + 'read_timeout': int(options['--read-timeout']), + 'port': int(options['--ipport']), +- 'ssl_verify': bool('--ssl-secure' in options), ++ 'ssl_verify': bool('--ssl-insecure' not in options), + } + try: + conn = APIClient(hmc_address, hmc_userid, hmc_password, config) +diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py +index 25aecbe58..5f74d06f6 100644 +--- a/agents/rhevm/fence_rhevm.py ++++ b/agents/rhevm/fence_rhevm.py +@@ -85,7 +85,7 @@ def send_command(opt, command, method="GET"): + logging.debug("auto-detected API version: " + opt["--api-version"]) + + ## setup correct URL +- if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt: ++ if "--ssl-secure" in opt or "--ssl-insecure" in opt: + url = "https:" + else: + url = "http:" +@@ -126,11 +126,11 @@ def send_command(opt, command, method="GET"): + conn.setopt(pycurl.COOKIEJAR, cookie_file) + + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) +- if "--ssl" in opt or "--ssl-secure" in opt: ++ ++ if "--ssl-secure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) +- +- if "--ssl-insecure" in opt: ++ elif "--ssl-insecure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + +diff --git a/agents/skalar/fence_skalar.py b/agents/skalar/fence_skalar.py +index 959527411..0e11d83f9 100644 +--- a/agents/skalar/fence_skalar.py ++++ b/agents/skalar/fence_skalar.py +@@ -200,7 +200,7 @@ def main(): + run_delay(options) + + proto = "https://" +- if "--ssl" in options or "--ssl-secure" in options: ++ if "--ssl-secure" in options: + ssl_verify = True + elif "--ssl-insecure" in options: + ssl_verify = False +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index e49fd5663..4b884fc62 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -69,7 +69,7 @@ def connect(opt): + conn = pycurl.Curl() + + ## setup correct URL +- if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt: ++ if "--ssl-secure" in opt or "--ssl-insecure" in opt: + conn.base_url = "https:" + else: + conn.base_url = "http:" +@@ -89,11 +89,11 @@ def connect(opt): + conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"]) + + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) +- if "--ssl" in opt or "--ssl-secure" in opt: ++ ++ if "--ssl-secure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) +- +- if "--ssl-insecure" in opt: ++ elif "--ssl-insecure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + +diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py +index 2cd45e0b3..51fb0f147 100644 +--- a/agents/vmware_soap/fence_vmware_soap.py ++++ b/agents/vmware_soap/fence_vmware_soap.py +@@ -34,7 +34,7 @@ def send(self, request): + def soap_login(options): + run_delay(options) + +- if "--ssl" in options or "--ssl-secure" in options or "--ssl-insecure" in options: ++ if "--ssl-secure" in options or "--ssl-insecure" in options: + if "--ssl-insecure" in options: + import ssl + import urllib3 +diff --git a/agents/vmware_vcloud/fence_vmware_vcloud.py b/agents/vmware_vcloud/fence_vmware_vcloud.py +index 42372a83d..7626b82bb 100644 +--- a/agents/vmware_vcloud/fence_vmware_vcloud.py ++++ b/agents/vmware_vcloud/fence_vmware_vcloud.py +@@ -60,7 +60,7 @@ def connect(opt): + conn = pycurl.Curl() + + ## setup correct URL +- if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt: ++ if "--ssl-secure" in opt or "--ssl-insecure" in opt: + conn.base_url = "https:" + else: + conn.base_url = "http:" +@@ -76,7 +76,7 @@ def connect(opt): + conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"]) + + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) +- if "--ssl" in opt or "--ssl-secure" in opt: ++ if "--ssl-secure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + elif "--ssl-insecure" in opt: +diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py +index e8f849eda..90ca95d45 100644 +--- a/agents/zvm/fence_zvmip.py ++++ b/agents/zvm/fence_zvmip.py +@@ -26,7 +26,7 @@ def open_socket(options): + except socket.gaierror: + fail(EC_LOGIN_DENIED) + +- if "--ssl" in options: ++ if "--ssl-secure" in options or "--ssl-insecure" in options: + import ssl + sock = socket.socket() + sslcx = ssl.create_default_context() +@@ -132,7 +132,7 @@ def get_list_of_images(options, command, data_as_plug): + images = set() + + if output_len > 3*INT4: +- recvflag = socket.MSG_WAITALL if "--ssl" not in options else 0 ++ recvflag = socket.MSG_WAITALL if "--ssl-secure" not in options and "--ssl-insecure" not in options else 0 + array_len = struct.unpack("!i", conn.recv(INT4))[0] + data = "" + +@@ -182,7 +182,9 @@ def main(): + options = check_input(device_opt, process_input(device_opt), other_conditions=True) + + if "--disable-ssl" in options or options["--ssl"] == "0": +- del options["--ssl"] ++ for k in ["--ssl", "--ssl-secure", "--ssl-insecure"]: ++ if k in options: ++ del options[k] + + if len(options.get("--plug", "")) > 8: + fail_usage("Failed: Name of image can not be longer than 8 characters") +diff --git a/lib/fencing.py.py b/lib/fencing.py.py +index 696388d55..b746ede8b 100644 +--- a/lib/fencing.py.py ++++ b/lib/fencing.py.py +@@ -789,6 +789,12 @@ def check_input(device_opt, opt, other_conditions = False): + if "--password-script" in options: + options["--password"] = os.popen(options["--password-script"]).read().rstrip() + ++ if "--ssl-secure" in options or "--ssl-insecure" in options: ++ options["--ssl"] = "" ++ ++ if "--ssl" in options and "--ssl-insecure" not in options: ++ options["--ssl-secure"] = "" ++ + if os.environ.get("PCMK_service") == "pacemaker-fenced" and "--disable-timeout" not in options: + options["--disable-timeout"] = "1" + +diff --git a/tests/data/metadata/fence_docker.xml b/tests/data/metadata/fence_docker.xml +index 723e72280..51c7c470a 100644 +--- a/tests/data/metadata/fence_docker.xml ++++ b/tests/data/metadata/fence_docker.xml +@@ -20,7 +20,7 @@ + + + +- ++ + TCP/UDP port to use for connection with device + + +@@ -43,7 +43,7 @@ + + + +- ++ + Use SSL connection with verifying certificate + + diff --git a/SOURCES/bz2072420-2-fence_zvmip-connect-error.patch b/SOURCES/bz2072420-2-fence_zvmip-connect-error.patch new file mode 100644 index 0000000..1a1bd97 --- /dev/null +++ b/SOURCES/bz2072420-2-fence_zvmip-connect-error.patch @@ -0,0 +1,30 @@ +From 6430104318b4bf349425b08636183bf839812e04 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 31 May 2022 08:55:25 +0200 +Subject: [PATCH] fence_zvmip: show unable to connect error instead of full + stacktrace, e.g. when not using --ssl for SSL devices + +--- + agents/zvm/fence_zvmip.py | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py +index 90ca95d45..4f538e10d 100644 +--- a/agents/zvm/fence_zvmip.py ++++ b/agents/zvm/fence_zvmip.py +@@ -127,8 +127,13 @@ def get_list_of_images(options, command, data_as_plug): + + conn.send(packet) + +- request_id = struct.unpack("!i", conn.recv(INT4))[0] +- (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4)) ++ try: ++ request_id = struct.unpack("!i", conn.recv(INT4))[0] ++ (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4)) ++ except struct.error: ++ logging.debug(sys.exc_info()) ++ fail_usage("Failed: Unable to connect to {} port: {} SSL: {} \n".format(options["--ip"], options["--ipport"], bool("--ssl" in options))) ++ + images = set() + + if output_len > 3*INT4: diff --git a/SOURCES/bz2079889-fence_gce-update.patch b/SOURCES/bz2079889-fence_gce-update.patch new file mode 100644 index 0000000..97e5193 --- /dev/null +++ b/SOURCES/bz2079889-fence_gce-update.patch @@ -0,0 +1,410 @@ +--- fence-agents-4.10.0/agents/gce/fence_gce.py 2022-04-29 10:13:50.317888041 +0200 ++++ fence-agents-4.10.0/agents/gce/fence_gce.py2 2022-04-29 10:17:54.813248566 +0200 +@@ -2,10 +2,10 @@ + + # + # Requires the googleapiclient and oauth2client +-# RHEL 7.x: google-api-python-client==1.6.7 python-gflags==2.0 pyasn1==0.4.8 rsa==3.4.2 +-# RHEL 8.x: nothing additional needed +-# SLES 12.x: python-google-api-python-client python-oauth2client python-oauth2client-gce +-# SLES 15.x: python3-google-api-python-client python3-oauth2client python3-oauth2client-gce ++# RHEL 7.x: google-api-python-client==1.6.7 python-gflags==2.0 pyasn1==0.4.8 rsa==3.4.2 pysocks==1.7.1 httplib2==0.19.0 ++# RHEL 8.x: pysocks==1.7.1 httplib2==0.19.0 ++# SLES 12.x: python-google-api-python-client python-oauth2client python-oauth2client-gce pysocks==1.7.1 httplib2==0.19.0 ++# SLES 15.x: python3-google-api-python-client python3-oauth2client pysocks==1.7.1 httplib2==0.19.0 + # + + import atexit +@@ -27,7 +27,7 @@ + import urllib2 as urlrequest + sys.path.append("@FENCEAGENTSLIBDIR@") + +-from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action ++from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action, run_command + try: + sys.path.insert(0, '/usr/lib/fence-agents/support/google') + import httplib2 +@@ -42,6 +42,19 @@ + + METADATA_SERVER = 'http://metadata.google.internal/computeMetadata/v1/' + METADATA_HEADERS = {'Metadata-Flavor': 'Google'} ++INSTANCE_LINK = 'https://www.googleapis.com/compute/v1/projects/{}/zones/{}/instances/{}' ++ ++def run_on_fail(options): ++ if "--runonfail" in options: ++ run_command(options, options["--runonfail"]) ++ ++def fail_fence_agent(options, message): ++ run_on_fail(options) ++ fail_usage(message) ++ ++def raise_fence_agent(options, message): ++ run_on_fail(options) ++ raise Exception(message) + + # + # Will use baremetalsolution setting or the environment variable +@@ -66,7 +79,7 @@ + { + "matchlength": 4, + "match": "https://compute.googleapis.com/compute/v1/projects/(.*)/zones/(.*)/instances/(.*)/reset(.*)", +- "replace": "https://baremetalsolution.googleapis.com/v1alpha1/projects/\\1/locations/\\2/instances/\\3:resetInstance\\4" ++ "replace": "https://baremetalsolution.googleapis.com/v1/projects/\\1/locations/\\2/instances/\\3:resetInstance\\4" + }) + for uri_replacement in uri_replacements: + # each uri_replacement should have matchlength, match, and replace +@@ -121,14 +134,17 @@ + + def get_nodes_list(conn, options): + result = {} ++ if "--zone" not in options: ++ fail_fence_agent(options, "Failed: get_nodes_list: Please specify the --zone in the command") + try: +- instanceList = retry_api_execute(options, conn.instances().list( +- project=options["--project"], +- zone=options["--zone"])) +- for instance in instanceList["items"]: +- result[instance["id"]] = (instance["name"], translate_status(instance["status"])) ++ for zone in options["--zone"].split(","): ++ instanceList = retry_api_execute(options, conn.instances().list( ++ project=options["--project"], ++ zone=zone)) ++ for instance in instanceList["items"]: ++ result[instance["id"]] = (instance["name"], translate_status(instance["status"])) + except Exception as err: +- fail_usage("Failed: get_nodes_list: {}".format(str(err))) ++ fail_fence_agent(options, "Failed: get_nodes_list: {}".format(str(err))) + + return result + +@@ -142,23 +158,54 @@ + return "off" + else: + return "on" ++ # If zone is not listed for an entry we attempt to get it automatically ++ instance = options["--plug"] ++ zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance] ++ instance_status = get_instance_power_status(conn, options, instance, zone) ++ # If any of the instances do not match the intended status we return the ++ # the opposite status so that the fence agent can change it. ++ if instance_status != options.get("--action"): ++ return instance_status ++ ++ return options.get("--action") ++ ++ ++def get_instance_power_status(conn, options, instance, zone): + try: +- instance = retry_api_execute(options, conn.instances().get( +- project=options["--project"], +- zone=options["--zone"], +- instance=options["--plug"])) ++ instance = retry_api_execute( ++ options, ++ conn.instances().get(project=options["--project"], zone=zone, instance=instance)) + return translate_status(instance["status"]) + except Exception as err: +- fail_usage("Failed: get_power_status: {}".format(str(err))) ++ fail_fence_agent(options, "Failed: get_instance_power_status: {}".format(str(err))) + + +-def wait_for_operation(conn, options, operation): ++def check_for_existing_operation(conn, options, instance, zone, operation_type): ++ logging.debug("check_for_existing_operation") ++ if "--baremetalsolution" in options: ++ # There is no API for checking in progress operations ++ return False ++ ++ project = options["--project"] ++ target_link = INSTANCE_LINK.format(project, zone, instance) ++ query_filter = '(targetLink = "{}") AND (operationType = "{}") AND (status = "RUNNING")'.format(target_link, operation_type) ++ result = retry_api_execute( ++ options, ++ conn.zoneOperations().list(project=project, zone=zone, filter=query_filter, maxResults=1)) ++ ++ if "items" in result and result["items"]: ++ logging.info("Existing %s operation found", operation_type) ++ return result["items"][0] ++ ++ ++def wait_for_operation(conn, options, zone, operation): + if 'name' not in operation: + logging.warning('Cannot wait for operation to complete, the' + ' requested operation will continue asynchronously') +- return ++ return False ++ ++ wait_time = 0 + project = options["--project"] +- zone = options["--zone"] + while True: + result = retry_api_execute(options, conn.zoneOperations().get( + project=project, +@@ -166,56 +213,93 @@ + operation=operation['name'])) + if result['status'] == 'DONE': + if 'error' in result: +- raise Exception(result['error']) +- return ++ raise_fence_agent(options, result['error']) ++ return True ++ ++ if "--errortimeout" in options and wait_time > int(options["--errortimeout"]): ++ raise_fence_agent(options, "Operation did not complete before the timeout.") ++ ++ if "--warntimeout" in options and wait_time > int(options["--warntimeout"]): ++ logging.warning("Operation did not complete before the timeout.") ++ if "--runonwarn" in options: ++ run_command(options, options["--runonwarn"]) ++ return False ++ ++ wait_time = wait_time + 1 + time.sleep(1) + + + def set_power_status(conn, options): +- logging.debug("set_power_status"); ++ logging.debug("set_power_status") ++ instance = options["--plug"] ++ # If zone is not listed for an entry we attempt to get it automatically ++ zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance] ++ set_instance_power_status(conn, options, instance, zone, options["--action"]) ++ ++ ++def set_instance_power_status(conn, options, instance, zone, action): ++ logging.info("Setting power status of %s in zone %s", instance, zone) ++ project = options["--project"] ++ + try: +- if options["--action"] == "off": +- logging.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"])) +- operation = retry_api_execute(options, conn.instances().stop( +- project=options["--project"], +- zone=options["--zone"], +- instance=options["--plug"])) ++ if action == "off": ++ logging.info("Issuing poweroff of %s in zone %s", instance, zone) ++ operation = check_for_existing_operation(conn, options, instance, zone, "stop") ++ if operation and "--earlyexit" in options: ++ return ++ if not operation: ++ operation = retry_api_execute( ++ options, ++ conn.instances().stop(project=project, zone=zone, instance=instance)) + logging.info("Poweroff command completed, waiting for the operation to complete") +- wait_for_operation(conn, options, operation) +- logging.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"])) +- elif options["--action"] == "on": +- logging.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"])) +- operation = retry_api_execute(options, conn.instances().start( +- project=options["--project"], +- zone=options["--zone"], +- instance=options["--plug"])) +- wait_for_operation(conn, options, operation) +- logging.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"])) ++ if wait_for_operation(conn, options, zone, operation): ++ logging.info("Poweroff of %s in zone %s complete", instance, zone) ++ elif action == "on": ++ logging.info("Issuing poweron of %s in zone %s", instance, zone) ++ operation = check_for_existing_operation(conn, options, instance, zone, "start") ++ if operation and "--earlyexit" in options: ++ return ++ if not operation: ++ operation = retry_api_execute( ++ options, ++ conn.instances().start(project=project, zone=zone, instance=instance)) ++ if wait_for_operation(conn, options, zone, operation): ++ logging.info("Poweron of %s in zone %s complete", instance, zone) + except Exception as err: +- fail_usage("Failed: set_power_status: {}".format(str(err))) +- ++ fail_fence_agent(options, "Failed: set_instance_power_status: {}".format(str(err))) + + def power_cycle(conn, options): +- logging.debug("power_cycle"); ++ logging.debug("power_cycle") ++ instance = options["--plug"] ++ # If zone is not listed for an entry we attempt to get it automatically ++ zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance] ++ return power_cycle_instance(conn, options, instance, zone) ++ ++ ++def power_cycle_instance(conn, options, instance, zone): ++ logging.info("Issuing reset of %s in zone %s", instance, zone) ++ project = options["--project"] ++ + try: +- logging.info('Issuing reset of %s in zone %s' % (options["--plug"], options["--zone"])) +- operation = retry_api_execute(options, conn.instances().reset( +- project=options["--project"], +- zone=options["--zone"], +- instance=options["--plug"])) +- logging.info("Reset command completed, waiting for the operation to complete") +- wait_for_operation(conn, options, operation) +- logging.info('Reset of %s in zone %s complete' % (options["--plug"], options["--zone"])) ++ operation = check_for_existing_operation(conn, options, instance, zone, "reset") ++ if operation and "--earlyexit" in options: ++ return True ++ if not operation: ++ operation = retry_api_execute( ++ options, ++ conn.instances().reset(project=project, zone=zone, instance=instance)) ++ logging.info("Reset command sent, waiting for the operation to complete") ++ if wait_for_operation(conn, options, zone, operation): ++ logging.info("Reset of %s in zone %s complete", instance, zone) + return True + except Exception as err: +- logging.error("Failed: power_cycle: {}".format(str(err))) +- return False ++ logging.exception("Failed: power_cycle") ++ raise err + + +-def get_zone(conn, options): ++def get_zone(conn, options, instance): + logging.debug("get_zone"); + project = options['--project'] +- instance = options['--plug'] + fl = 'name="%s"' % instance + request = replace_api_uri(options, conn.instances().aggregatedList(project=project, filter=fl)) + while request is not None: +@@ -227,7 +311,7 @@ + return inst['zone'].split("/")[-1] + request = replace_api_uri(options, conn.instances().aggregatedList_next( + previous_request=request, previous_response=response)) +- raise Exception("Unable to find instance %s" % (instance)) ++ raise_fence_agent(options, "Unable to find instance %s" % (instance)) + + + def get_metadata(metadata_key, params=None, timeout=None): +@@ -326,13 +410,21 @@ + "required" : "0", + "order" : 9 + } ++ all_opt["plugzonemap"] = { ++ "getopt" : ":", ++ "longopt" : "plugzonemap", ++ "help" : "--plugzonemap=[plugzonemap] Comma separated zone map when fencing multiple plugs", ++ "shortdesc" : "Comma separated zone map when fencing multiple plugs.", ++ "required" : "0", ++ "order" : 10 ++ } + all_opt["proxyhost"] = { + "getopt" : ":", + "longopt" : "proxyhost", + "help" : "--proxyhost=[proxy_host] The proxy host to use, if one is needed to access the internet (Example: 10.122.0.33)", + "shortdesc" : "If a proxy is used for internet access, the proxy host should be specified.", + "required" : "0", +- "order" : 10 ++ "order" : 11 + } + all_opt["proxyport"] = { + "getopt" : ":", +@@ -341,7 +433,49 @@ + "help" : "--proxyport=[proxy_port] The proxy port to use, if one is needed to access the internet (Example: 3127)", + "shortdesc" : "If a proxy is used for internet access, the proxy port should be specified.", + "required" : "0", +- "order" : 11 ++ "order" : 12 ++ } ++ all_opt["earlyexit"] = { ++ "getopt" : "", ++ "longopt" : "earlyexit", ++ "help" : "--earlyexit Return early if reset is already in progress", ++ "shortdesc" : "If an existing reset operation is detected, the fence agent will return before the operation completes with a 0 return code.", ++ "required" : "0", ++ "order" : 13 ++ } ++ all_opt["warntimeout"] = { ++ "getopt" : ":", ++ "type" : "second", ++ "longopt" : "warntimeout", ++ "help" : "--warntimeout=[warn_timeout] Timeout seconds before logging a warning and returning a 0 status code", ++ "shortdesc" : "If the operation is not completed within the timeout, the cluster operations are allowed to continue.", ++ "required" : "0", ++ "order" : 14 ++ } ++ all_opt["errortimeout"] = { ++ "getopt" : ":", ++ "type" : "second", ++ "longopt" : "errortimeout", ++ "help" : "--errortimeout=[error_timeout] Timeout seconds before failing and returning a non-zero status code", ++ "shortdesc" : "If the operation is not completed within the timeout, cluster is notified of the operation failure.", ++ "required" : "0", ++ "order" : 15 ++ } ++ all_opt["runonwarn"] = { ++ "getopt" : ":", ++ "longopt" : "runonwarn", ++ "help" : "--runonwarn=[run_on_warn] If a timeout occurs and warning is generated, run the supplied command", ++ "shortdesc" : "If a timeout would occur while running the agent, then the supplied command is run.", ++ "required" : "0", ++ "order" : 16 ++ } ++ all_opt["runonfail"] = { ++ "getopt" : ":", ++ "longopt" : "runonfail", ++ "help" : "--runonfail=[run_on_fail] If a failure occurs, run the supplied command", ++ "shortdesc" : "If a failure would occur while running the agent, then the supplied command is run.", ++ "required" : "0", ++ "order" : 17 + } + + +@@ -350,7 +484,8 @@ + + device_opt = ["port", "no_password", "zone", "project", "stackdriver-logging", + "method", "baremetalsolution", "apitimeout", "retries", "retrysleep", +- "serviceaccount", "proxyhost", "proxyport"] ++ "serviceaccount", "plugzonemap", "proxyhost", "proxyport", "earlyexit", ++ "warntimeout", "errortimeout", "runonwarn", "runonfail"] + + atexit.register(atexit_handler) + +@@ -431,22 +566,39 @@ + conn = googleapiclient.discovery.build( + 'compute', 'v1', credentials=credentials, cache_discovery=False) + except Exception as err: +- fail_usage("Failed: Create GCE compute v1 connection: {}".format(str(err))) ++ fail_fence_agent(options, "Failed: Create GCE compute v1 connection: {}".format(str(err))) + + # Get project and zone + if not options.get("--project"): + try: + options["--project"] = get_metadata('project/project-id') + except Exception as err: +- fail_usage("Failed retrieving GCE project. Please provide --project option: {}".format(str(err))) ++ fail_fence_agent(options, "Failed retrieving GCE project. Please provide --project option: {}".format(str(err))) + + if "--baremetalsolution" in options: + options["--zone"] = "none" +- if not options.get("--zone"): +- try: +- options["--zone"] = get_zone(conn, options) +- except Exception as err: +- fail_usage("Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err))) ++ ++ # Populates zone automatically if missing from the command ++ zones = [] if not "--zone" in options else options["--zone"].split(",") ++ options["--plugzonemap"] = {} ++ if "--plug" in options: ++ for i, instance in enumerate(options["--plug"].split(",")): ++ if len(zones) == 1: ++ # If only one zone is specified, use it across all plugs ++ options["--plugzonemap"][instance] = zones[0] ++ continue ++ ++ if len(zones) - 1 >= i: ++ # If we have enough zones specified with the --zone flag use the zone at ++ # the same index as the plug ++ options["--plugzonemap"][instance] = zones[i] ++ continue ++ ++ try: ++ # In this case we do not have a zone specified so we attempt to detect it ++ options["--plugzonemap"][instance] = get_zone(conn, options, instance) ++ except Exception as err: ++ fail_fence_agent(options, "Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err))) + + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list, power_cycle) diff --git a/SOURCES/bz2081235-fence_ibm_vpc-fix-parameters.patch b/SOURCES/bz2081235-fence_ibm_vpc-fix-parameters.patch new file mode 100644 index 0000000..5e031ad --- /dev/null +++ b/SOURCES/bz2081235-fence_ibm_vpc-fix-parameters.patch @@ -0,0 +1,65 @@ +From d0254345472c9415af1e06e9e8df2fe0ce464db0 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 2 May 2022 11:14:42 +0200 +Subject: [PATCH] fence_ibm_vpc: remove unused instance parameter and make + limit optional + +--- + agents/ibm_vpc/fence_ibm_vpc.py | 11 +---------- + tests/data/metadata/fence_ibm_vpc.xml | 7 +------ + 2 files changed, 2 insertions(+), 16 deletions(-) + +diff --git a/agents/ibm_vpc/fence_ibm_vpc.py b/agents/ibm_vpc/fence_ibm_vpc.py +index 9f84f7b2d..9e38e8301 100755 +--- a/agents/ibm_vpc/fence_ibm_vpc.py ++++ b/agents/ibm_vpc/fence_ibm_vpc.py +@@ -161,14 +161,6 @@ def define_new_opts(): + "shortdesc" : "API Key", + "order" : 0 + } +- all_opt["instance"] = { +- "getopt" : ":", +- "longopt" : "instance", +- "help" : "--instance=[instance] Cloud Instance", +- "required" : "1", +- "shortdesc" : "Cloud Instance", +- "order" : 0 +- } + all_opt["region"] = { + "getopt" : ":", + "longopt" : "region", +@@ -181,7 +173,7 @@ def define_new_opts(): + "getopt" : ":", + "longopt" : "limit", + "help" : "--limit=[number] Limit number of nodes returned by API", +- "required" : "1", ++ "required" : "0", + "default": 50, + "shortdesc" : "Number of nodes returned by API", + "order" : 0 +@@ -191,7 +183,6 @@ def define_new_opts(): + def main(): + device_opt = [ + "apikey", +- "instance", + "region", + "limit", + "port", +diff --git a/tests/data/metadata/fence_ibm_vpc.xml b/tests/data/metadata/fence_ibm_vpc.xml +index 926efcaa0..ee7151673 100644 +--- a/tests/data/metadata/fence_ibm_vpc.xml ++++ b/tests/data/metadata/fence_ibm_vpc.xml +@@ -8,12 +8,7 @@ + + API Key + +- +- +- +- Cloud Instance +- +- ++ + + + Number of nodes returned by API diff --git a/SOURCES/bz2086559-fence_apc-fence_ilo_moonshot-import-logging.patch b/SOURCES/bz2086559-fence_apc-fence_ilo_moonshot-import-logging.patch new file mode 100644 index 0000000..dbbde08 --- /dev/null +++ b/SOURCES/bz2086559-fence_apc-fence_ilo_moonshot-import-logging.patch @@ -0,0 +1,34 @@ +From 6ea2c6b5d1cc51e93fa7084d76d9272512461e58 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 16 May 2022 11:01:21 +0200 +Subject: [PATCH] fence_apc/fence_ilo_moonshot: add missing "import logging" + +--- + agents/apc/fence_apc.py | 1 + + agents/ilo_moonshot/fence_ilo_moonshot.py | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/agents/apc/fence_apc.py b/agents/apc/fence_apc.py +index 901aad25e..3ea0f37d6 100644 +--- a/agents/apc/fence_apc.py ++++ b/agents/apc/fence_apc.py +@@ -15,6 +15,7 @@ + ##### + + import sys, re, time ++import logging + import atexit + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * +diff --git a/agents/ilo_moonshot/fence_ilo_moonshot.py b/agents/ilo_moonshot/fence_ilo_moonshot.py +index 6f5cca320..1923eeb1c 100644 +--- a/agents/ilo_moonshot/fence_ilo_moonshot.py ++++ b/agents/ilo_moonshot/fence_ilo_moonshot.py +@@ -1,6 +1,7 @@ + #!@PYTHON@ -tt + + import sys ++import logging + import atexit + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * diff --git a/SOURCES/bz2092385-fence_ibm_vpc-add-proxy-support.patch b/SOURCES/bz2092385-fence_ibm_vpc-add-proxy-support.patch new file mode 100644 index 0000000..39a2e2e --- /dev/null +++ b/SOURCES/bz2092385-fence_ibm_vpc-add-proxy-support.patch @@ -0,0 +1,62 @@ +From be409554bbc99df2bba22cb01e8a6df634af896d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 31 May 2022 15:46:40 +0200 +Subject: [PATCH] fence_ibm_vpc: add proxy support + +--- + agents/ibm_vpc/fence_ibm_vpc.py | 11 +++++++++++ + tests/data/metadata/fence_ibm_vpc.xml | 5 +++++ + 2 files changed, 16 insertions(+) + +diff --git a/agents/ibm_vpc/fence_ibm_vpc.py b/agents/ibm_vpc/fence_ibm_vpc.py +index 9e38e8301..3da3ce056 100755 +--- a/agents/ibm_vpc/fence_ibm_vpc.py ++++ b/agents/ibm_vpc/fence_ibm_vpc.py +@@ -88,6 +88,7 @@ def connect(opt): + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) ++ conn.setopt(pycurl.PROXY, "{}".format(opt["--proxy"])) + + # get bearer token + bearer_token = get_bearer_token(conn, opt) +@@ -169,6 +170,15 @@ def define_new_opts(): + "shortdesc" : "Region", + "order" : 0 + } ++ all_opt["proxy"] = { ++ "getopt" : ":", ++ "longopt" : "proxy", ++ "help" : "--proxy=[http://:] Proxy: 'http://:'", ++ "required" : "0", ++ "default": "", ++ "shortdesc" : "Network proxy", ++ "order" : 0 ++ } + all_opt["limit"] = { + "getopt" : ":", + "longopt" : "limit", +@@ -185,6 +195,7 @@ def main(): + "apikey", + "region", + "limit", ++ "proxy", + "port", + "no_password", + ] +diff --git a/tests/data/metadata/fence_ibm_vpc.xml b/tests/data/metadata/fence_ibm_vpc.xml +index ee7151673..09da0e303 100644 +--- a/tests/data/metadata/fence_ibm_vpc.xml ++++ b/tests/data/metadata/fence_ibm_vpc.xml +@@ -13,6 +13,11 @@ + + Number of nodes returned by API + ++ ++ ++ ++ Network proxy ++ + + + diff --git a/SOURCES/bz2093216-fence_ibm_powervs-proxy-private-api-servers.patch b/SOURCES/bz2093216-fence_ibm_powervs-proxy-private-api-servers.patch new file mode 100644 index 0000000..36f07fc --- /dev/null +++ b/SOURCES/bz2093216-fence_ibm_powervs-proxy-private-api-servers.patch @@ -0,0 +1,455 @@ +From 98fec5c6d55369ad681abc0cde0d8677835957ab Mon Sep 17 00:00:00 2001 +From: Arnold Beilmann +Date: Thu, 5 May 2022 15:26:22 +0200 +Subject: [PATCH 1/2] modified for PowerVS + +--- + agents/ibm_powervs/fence_ibm_powervs.py | 108 +++++++++++++++++++----- + 1 file changed, 89 insertions(+), 19 deletions(-) + +diff --git a/agents/ibm_powervs/fence_ibm_powervs.py b/agents/ibm_powervs/fence_ibm_powervs.py +index 6649771ea..727009220 100755 +--- a/agents/ibm_powervs/fence_ibm_powervs.py ++++ b/agents/ibm_powervs/fence_ibm_powervs.py +@@ -1,10 +1,11 @@ +-#!@PYTHON@ -tt ++#!/usr/libexec/platform-python -tt + + import sys + import pycurl, io, json + import logging + import atexit +-sys.path.append("@FENCEAGENTSLIBDIR@") ++import time ++sys.path.append("/usr/share/fence") + from fencing import * + from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS + +@@ -14,16 +15,30 @@ + "ERROR": "unknown" + } + ++def get_token(conn, options): ++ ++ try: ++ command = "identity/token" ++ action = "grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey={}".format(options["--token"]) ++ res = send_command(conn, command, "POST", action, printResult=False) ++ except Exception as e: ++ logging.debug("Failed: {}".format(e)) ++ return "TOKEN_IS_MISSING_OR_WRONG" ++ ++ #if "--verbose" in options: ++ # logging.debug(json.dumps(res, indent=2)) ++ ++ return res["access_token"] ++ + def get_list(conn, options): + outlets = {} +- ++ + try: + command = "cloud-instances/{}/pvm-instances".format(options["--instance"]) + res = send_command(conn, command) + except Exception as e: + logging.debug("Failed: {}".format(e)) + return outlets +- + for r in res["pvmInstances"]: + if "--verbose" in options: + logging.debug(json.dumps(r, indent=2)) +@@ -32,6 +47,7 @@ def get_list(conn, options): + return outlets + + def get_power_status(conn, options): ++ + try: + command = "cloud-instances/{}/pvm-instances/{}".format( + options["--instance"], options["--plug"]) +@@ -40,10 +56,11 @@ def get_power_status(conn, options): + except KeyError as e: + logging.debug("Failed: Unable to get status for {}".format(e)) + fail(EC_STATUS) +- ++ + return result + + def set_power_status(conn, options): ++ + action = { + "on" : '{"action" : "start"}', + "off" : '{"action" : "immediate-shutdown"}', +@@ -56,35 +73,63 @@ def set_power_status(conn, options): + logging.debug("Failed: Unable to set power to {} for {}".format(options["--action"], e)) + fail(EC_STATUS) + +-def connect(opt): ++def connect(opt, token): + conn = pycurl.Curl() + + ## setup correct URL +- conn.base_url = "https://" + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" ++ conn.base_url = "https://private." + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" ++ if opt["--api-type"] == "public": ++ conn.base_url = "https://" + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" + + if opt["--verbose-level"] > 1: +- conn.setopt(pycurl.VERBOSE, 1) ++ conn.setopt(pycurl.VERBOSE, 0) + ++ conn.setopt(pycurl.CONNECTTIMEOUT,int(opt["--shell-timeout"])) + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) ++ conn.setopt(pycurl.PROXY, "{}".format(opt["--proxy"])) + + # set auth token for later requests + conn.setopt(pycurl.HTTPHEADER, [ + "Content-Type: application/json", +- "Authorization: Bearer {}".format(opt["--token"]), ++ "Authorization: Bearer {}".format(token), + "CRN: {}".format(opt["--crn"]), + "User-Agent: curl", + ]) ++ ++ return conn ++ ++def auth_connect(opt): ++ conn = pycurl.Curl() ++ ++ # setup correct URL ++ conn.base_url = "https://iam.cloud.ibm.com/" ++ ++ if opt["--verbose-level"] > 1: ++ conn.setopt(pycurl.VERBOSE, 1) ++ ++ conn.setopt(pycurl.CONNECTTIMEOUT,int(opt["--shell-timeout"])) ++ conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) ++ conn.setopt(pycurl.SSL_VERIFYPEER, 1) ++ conn.setopt(pycurl.SSL_VERIFYHOST, 2) ++ conn.setopt(pycurl.PROXY, "{}".format(opt["--proxy"])) ++ ++ # set auth token for later requests ++ conn.setopt(pycurl.HTTPHEADER, [ ++ "Content-type: application/x-www-form-urlencoded", ++ "Accept: application/json", ++ "User-Agent: curl", ++ ]) + + return conn + + def disconnect(conn): + conn.close() + +-def send_command(conn, command, method="GET", action=None): ++def send_command(conn, command, method="GET", action=None, printResult=True): + url = conn.base_url + command +- ++ + conn.setopt(pycurl.URL, url.encode("ascii")) + + web_buffer = io.BytesIO() +@@ -99,8 +144,10 @@ def send_command(conn, command, method="GET", action=None): + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + + try: ++ time.sleep(3) + conn.perform() + except Exception as e: ++ logging.error("ADD_DEBUG: {}".format(e)) + raise(e) + + rc = conn.getinfo(pycurl.HTTP_CODE) +@@ -110,8 +157,7 @@ def send_command(conn, command, method="GET", action=None): + + if rc != 200: + if len(result) > 0: +- raise Exception("{}: {}".format(rc, +- result["value"]["messages"][0]["default_message"])) ++ raise Exception("{}: {}".format(rc,result)) + else: + raise Exception("Remote returned {} for request to {}".format(rc, url)) + +@@ -121,7 +167,8 @@ def send_command(conn, command, method="GET", action=None): + logging.debug("url: {}".format(url)) + logging.debug("method: {}".format(method)) + logging.debug("response code: {}".format(rc)) +- logging.debug("result: {}\n".format(result)) ++ if printResult: ++ logging.debug("result: {}\n".format(result)) + + return result + +@@ -129,9 +176,9 @@ def define_new_opts(): + all_opt["token"] = { + "getopt" : ":", + "longopt" : "token", +- "help" : "--token=[token] Bearer Token", ++ "help" : "--token=[token] API Token", + "required" : "1", +- "shortdesc" : "Bearer Token", ++ "shortdesc" : "API Token", + "order" : 0 + } + all_opt["crn"] = { +@@ -158,6 +205,22 @@ def define_new_opts(): + "shortdesc" : "Region", + "order" : 0 + } ++ all_opt["api-type"] = { ++ "getopt" : ":", ++ "longopt" : "api-type", ++ "help" : "--api-type=[private|public] API-type: 'private' (default) or 'public'", ++ "required" : "0", ++ "shortdesc" : "API-type (private|public)", ++ "order" : 0 ++ } ++ all_opt["proxy"] = { ++ "getopt" : ":", ++ "longopt" : "proxy", ++ "help" : "--proxy=[http://:] Proxy: 'http://:'", ++ "required" : "0", ++ "shortdesc" : "Network proxy", ++ "order" : 0 ++ } + + + def main(): +@@ -166,6 +229,8 @@ def main(): + "crn", + "instance", + "region", ++ "api-type", ++ "proxy", + "port", + "no_password", + ] +@@ -173,9 +238,11 @@ def main(): + atexit.register(atexit_handler) + define_new_opts() + +- all_opt["shell_timeout"]["default"] = "15" ++ all_opt["shell_timeout"]["default"] = "500" + all_opt["power_timeout"]["default"] = "30" + all_opt["power_wait"]["default"] = "1" ++ all_opt["api-type"]["default"] = "private" ++ all_opt["proxy"]["default"] = "" + + options = check_input(device_opt, process_input(device_opt)) + +@@ -190,8 +257,11 @@ def main(): + ## Fence operations + #### + run_delay(options) +- +- conn = connect(options) ++ ++ auth_conn = auth_connect(options) ++ token = get_token(auth_conn, options) ++ disconnect(auth_conn) ++ conn = connect(options, token) + atexit.register(disconnect, conn) + + result = fence_action(conn, options, set_power_status, get_power_status, get_list) + +From fbe9a539ac8f40686a8027b7e768d9f7b799e485 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 6 May 2022 11:22:47 +0200 +Subject: [PATCH 2/2] fence_ibm_powervs: cleanup and fixes + +--- + agents/ibm_powervs/fence_ibm_powervs.py | 37 ++++++++++------------- + tests/data/metadata/fence_ibm_powervs.xml | 19 ++++++++++-- + 2 files changed, 33 insertions(+), 23 deletions(-) + +diff --git a/agents/ibm_powervs/fence_ibm_powervs.py b/agents/ibm_powervs/fence_ibm_powervs.py +index 727009220..819ab8896 100755 +--- a/agents/ibm_powervs/fence_ibm_powervs.py ++++ b/agents/ibm_powervs/fence_ibm_powervs.py +@@ -1,11 +1,11 @@ +-#!/usr/libexec/platform-python -tt ++#!@PYTHON@ -tt + + import sys + import pycurl, io, json + import logging + import atexit + import time +-sys.path.append("/usr/share/fence") ++sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * + from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS + +@@ -16,7 +16,6 @@ + } + + def get_token(conn, options): +- + try: + command = "identity/token" + action = "grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey={}".format(options["--token"]) +@@ -25,20 +24,18 @@ def get_token(conn, options): + logging.debug("Failed: {}".format(e)) + return "TOKEN_IS_MISSING_OR_WRONG" + +- #if "--verbose" in options: +- # logging.debug(json.dumps(res, indent=2)) +- + return res["access_token"] + + def get_list(conn, options): + outlets = {} +- ++ + try: + command = "cloud-instances/{}/pvm-instances".format(options["--instance"]) + res = send_command(conn, command) + except Exception as e: + logging.debug("Failed: {}".format(e)) + return outlets ++ + for r in res["pvmInstances"]: + if "--verbose" in options: + logging.debug(json.dumps(r, indent=2)) +@@ -47,7 +44,6 @@ def get_list(conn, options): + return outlets + + def get_power_status(conn, options): +- + try: + command = "cloud-instances/{}/pvm-instances/{}".format( + options["--instance"], options["--plug"]) +@@ -56,11 +52,10 @@ def get_power_status(conn, options): + except KeyError as e: + logging.debug("Failed: Unable to get status for {}".format(e)) + fail(EC_STATUS) +- ++ + return result + + def set_power_status(conn, options): +- + action = { + "on" : '{"action" : "start"}', + "off" : '{"action" : "immediate-shutdown"}', +@@ -77,11 +72,11 @@ def connect(opt, token): + conn = pycurl.Curl() + + ## setup correct URL +- conn.base_url = "https://private." + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" +- if opt["--api-type"] == "public": +- conn.base_url = "https://" + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" ++ conn.base_url = "https://" + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" ++ if opt["--api-type"] == "private": ++ conn.base_url = "https://private." + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" + +- if opt["--verbose-level"] > 1: ++ if opt["--verbose-level"] < 3: + conn.setopt(pycurl.VERBOSE, 0) + + conn.setopt(pycurl.CONNECTTIMEOUT,int(opt["--shell-timeout"])) +@@ -129,7 +124,7 @@ def disconnect(conn): + + def send_command(conn, command, method="GET", action=None, printResult=True): + url = conn.base_url + command +- ++ + conn.setopt(pycurl.URL, url.encode("ascii")) + + web_buffer = io.BytesIO() +@@ -144,10 +139,9 @@ def send_command(conn, command, method="GET", action=None, printResult=True): + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + + try: +- time.sleep(3) + conn.perform() + except Exception as e: +- logging.error("ADD_DEBUG: {}".format(e)) ++ logging.error("send_command(): {}".format(e)) + raise(e) + + rc = conn.getinfo(pycurl.HTTP_CODE) +@@ -208,9 +202,9 @@ def define_new_opts(): + all_opt["api-type"] = { + "getopt" : ":", + "longopt" : "api-type", +- "help" : "--api-type=[private|public] API-type: 'private' (default) or 'public'", ++ "help" : "--api-type=[public|private] API-type: 'public' (default) or 'private'", + "required" : "0", +- "shortdesc" : "API-type (private|public)", ++ "shortdesc" : "API-type (public|private)", + "order" : 0 + } + all_opt["proxy"] = { +@@ -238,9 +232,10 @@ def main(): + atexit.register(atexit_handler) + define_new_opts() + +- all_opt["shell_timeout"]["default"] = "500" ++ all_opt["shell_timeout"]["default"] = "15" + all_opt["power_timeout"]["default"] = "30" + all_opt["power_wait"]["default"] = "1" ++ all_opt["stonith_status_sleep"]["default"] = "3" + all_opt["api-type"]["default"] = "private" + all_opt["proxy"]["default"] = "" + +@@ -257,7 +252,7 @@ def main(): + ## Fence operations + #### + run_delay(options) +- ++ + auth_conn = auth_connect(options) + token = get_token(auth_conn, options) + disconnect(auth_conn) +diff --git a/tests/data/metadata/fence_ibm_powervs.xml b/tests/data/metadata/fence_ibm_powervs.xml +index fe86331bd..81cea4379 100644 +--- a/tests/data/metadata/fence_ibm_powervs.xml ++++ b/tests/data/metadata/fence_ibm_powervs.xml +@@ -3,6 +3,16 @@ + fence_ibm_powervs is an I/O Fencing agent which can be used with IBM PowerVS to fence virtual machines. + https://www.ibm.com + ++ ++ ++ ++ API-type (public|private) ++ ++ ++ ++ ++ API-type (public|private) ++ + + + +@@ -13,6 +23,11 @@ + + PowerVS Instance + ++ ++ ++ ++ Network proxy ++ + + + +@@ -21,7 +36,7 @@ + + + +- Bearer Token ++ API Token + + + +@@ -110,7 +125,7 @@ + + + +- ++ + Sleep X seconds between status calls during a STONITH action + + diff --git a/SOURCES/ha-openstack-support.patch b/SOURCES/ha-openstack-support.patch deleted file mode 100644 index 741d90a..0000000 --- a/SOURCES/ha-openstack-support.patch +++ /dev/null @@ -1,30 +0,0 @@ ---- a/agents/compute/fence_compute.py 2021-03-04 15:11:13.867362945 +0100 -+++ b/agents/compute/fence_compute.py 2021-03-04 15:11:11.480357409 +0100 -@@ -253,6 +253,7 @@ - nova = None - - try: -+ sys.path.insert(0, '/usr/lib/fence-agents/support/openstack') - from novaclient import client - from novaclient.exceptions import NotAcceptable - except ImportError: ---- a/agents/evacuate/fence_evacuate.py 2021-03-04 15:11:48.267442726 +0100 -+++ b/agents/evacuate/fence_evacuate.py 2021-03-04 15:11:45.397436069 +0100 -@@ -189,6 +189,7 @@ - nova = None - - try: -+ sys.path.insert(0, '/usr/lib/fence-agents/support/openstack') - from novaclient import client - from novaclient.exceptions import NotAcceptable - except ImportError: ---- a/agents/openstack/fence_openstack.py 2021-06-03 11:48:01.000000000 +0200 -+++ b/agents/openstack/fence_openstack.py 2021-06-30 09:13:16.598937530 +0200 -@@ -11,6 +11,7 @@ - from fencing import fail_usage, run_delay - - try: -+ sys.path.insert(0, '/usr/lib/fence-agents/support/openstack') - from novaclient import client - from novaclient.exceptions import Conflict, NotFound - except ImportError: diff --git a/SOURCES/requirements-openstack.txt b/SOURCES/requirements-openstack.txt deleted file mode 100644 index 97da9af..0000000 --- a/SOURCES/requirements-openstack.txt +++ /dev/null @@ -1,3 +0,0 @@ -python-novaclient -python-keystoneclient -PyYAML==5.1 diff --git a/SPECS/fence-agents.spec b/SPECS/fence-agents.spec index afc34cb..735d249 100644 --- a/SPECS/fence-agents.spec +++ b/SPECS/fence-agents.spec @@ -28,7 +28,7 @@ %global dateutil dateutil %global dateutil_version 2.8.2 %global pyyaml PyYAML -%global pyyaml_version 6.0 +%global pyyaml_version 5.1 %global six six %global six_version 1.16.0 %global urllib3 urllib3 @@ -59,7 +59,7 @@ Name: fence-agents Summary: Set of unified programs capable of host isolation ("fencing") Version: 4.10.0 -Release: 20%{?alphatag:.%{alphatag}}%{?dist} +Release: 30%{?alphatag:.%{alphatag}}%{?dist} License: GPLv2+ and LGPLv2+ URL: https://github.com/ClusterLabs/fence-agents Source0: https://fedorahosted.org/releases/f/e/fence-agents/%{name}-%{version}.tar.gz @@ -68,8 +68,7 @@ Source100: requirements-aliyun.txt Source101: requirements-aws.txt Source102: requirements-azure.txt Source103: requirements-google.txt -Source104: requirements-openstack.txt -Source105: requirements-common.txt +Source104: requirements-common.txt ### HA support libs/utils ### # awscli 2+ is only available from github (and needs to be renamed from aws-cli... to awscli) Source900: awscli-2.2.15.tar.gz @@ -145,81 +144,56 @@ Source1059: pytz-2021.1-py2.py3-none-any.whl Source1060: rsa-4.7.2-py3-none-any.whl Source1061: setuptools-57.0.0-py3-none-any.whl Source1062: uritemplate-3.0.1-py2.py3-none-any.whl -# openstack -Source1063: PyYAML-5.1.tar.gz -Source1064: charset_normalizer-2.0.4-py3-none-any.whl -Source1065: debtcollector-2.2.0-py3-none-any.whl -Source1066: idna-3.2-py3-none-any.whl -Source1067: iso8601-0.1.16-py2.py3-none-any.whl -Source1068: keystoneauth1-4.3.1-py3-none-any.whl -Source1069: msgpack-1.0.2.tar.gz -Source1070: netaddr-0.8.0-py2.py3-none-any.whl -Source1071: netifaces-0.11.0.tar.gz -Source1072: oslo.config-8.7.1-py3-none-any.whl -Source1073: oslo.i18n-5.0.1-py3-none-any.whl -Source1074: oslo.serialization-4.2.0-py3-none-any.whl -Source1075: oslo.utils-4.10.0-py3-none-any.whl -Source1076: os_service_types-1.7.0-py2.py3-none-any.whl -Source1077: pbr-5.6.0-py2.py3-none-any.whl -Source1078: packaging-21.0-py3-none-any.whl -Source1079: prettytable-2.2.0-py3-none-any.whl -Source1080: python_keystoneclient-4.2.0-py3-none-any.whl -Source1081: python_novaclient-17.5.0-py3-none-any.whl -Source1082: requests-2.26.0-py2.py3-none-any.whl -Source1083: rfc3986-1.5.0-py2.py3-none-any.whl -Source1084: stevedore-3.4.0-py3-none-any.whl -Source1085: wcwidth-0.2.5-py2.py3-none-any.whl -Source1086: wheel-0.37.0-py2.py3-none-any.whl -Source1087: wrapt-1.12.1.tar.gz # common (pexpect / suds) -Source1088: pexpect-4.8.0-py2.py3-none-any.whl -Source1089: ptyprocess-0.7.0-py2.py3-none-any.whl -Source1090: suds_community-0.8.5-py3-none-any.whl +Source1063: pexpect-4.8.0-py2.py3-none-any.whl +Source1064: ptyprocess-0.7.0-py2.py3-none-any.whl +Source1065: suds_community-0.8.5-py3-none-any.whl ### END ### # kubevirt ## pip download --no-binary :all: openshift "ruamel.yaml.clib>=0.1.2" ### BEGIN -Source1091: %{openshift}-%{openshift_version}.tar.gz -Source1092: %{ruamelyamlclib}-%{ruamelyamlclib_version}.tar.gz -Source1093: %{kubernetes}-%{kubernetes_version}.tar.gz -Source1094: %{certifi}-%{certifi_version}.tar.gz -Source1095: %{googleauth}-%{googleauth_version}.tar.gz -Source1096: %{cachetools}-%{cachetools_version}.tar.gz -Source1097: %{pyasn1modules}-%{pyasn1modules_version}.tar.gz -Source1098: %{pyasn1}-%{pyasn1_version}.tar.gz -Source1099: python-%{dateutil}-%{dateutil_version}.tar.gz -Source1100: %{pyyaml}-%{pyyaml_version}.tar.gz +Source1066: %{openshift}-%{openshift_version}.tar.gz +Source1067: %{ruamelyamlclib}-%{ruamelyamlclib_version}.tar.gz +Source1068: %{kubernetes}-%{kubernetes_version}.tar.gz +Source1069: %{certifi}-%{certifi_version}.tar.gz +Source1070: %{googleauth}-%{googleauth_version}.tar.gz +Source1071: %{cachetools}-%{cachetools_version}.tar.gz +Source1072: %{pyasn1modules}-%{pyasn1modules_version}.tar.gz +Source1073: %{pyasn1}-%{pyasn1_version}.tar.gz +Source1074: python-%{dateutil}-%{dateutil_version}.tar.gz +Source1075: %{pyyaml}-%{pyyaml_version}.tar.gz ## rsa is dependency for "pip install", ## but gets removed to use cryptography lib instead -Source1101: rsa-4.7.2.tar.gz -Source1102: %{six}-%{six_version}.tar.gz -Source1103: %{urllib3}-%{urllib3_version}.tar.gz -Source1104: %{websocketclient}-%{websocketclient_version}.tar.gz -Source1105: %{jinja2}-%{jinja2_version}.tar.gz -Source1106: %{markupsafe}-%{markupsafe_version}.tar.gz -Source1107: python-%{stringutils}-%{stringutils_version}.tar.gz -Source1108: %{requests}-%{requests_version}.tar.gz -Source1109: %{chrstnormalizer}-%{chrstnormalizer_version}.tar.gz -Source1110: %{idna}-%{idna_version}.tar.gz -Source1111: %{reqstsoauthlib}-%{reqstsoauthlib_version}.tar.gz -Source1112: %{oauthlib}-%{oauthlib_version}.tar.gz -Source1113: %{ruamelyaml}-%{ruamelyaml_version}.tar.gz -Source1114: %{setuptools}-%{setuptools_version}.tar.gz +Source1076: rsa-4.7.2.tar.gz +Source1077: %{six}-%{six_version}.tar.gz +Source1078: %{urllib3}-%{urllib3_version}.tar.gz +Source1079: %{websocketclient}-%{websocketclient_version}.tar.gz +Source1080: %{jinja2}-%{jinja2_version}.tar.gz +Source1081: %{markupsafe}-%{markupsafe_version}.tar.gz +Source1082: python-%{stringutils}-%{stringutils_version}.tar.gz +Source1083: %{requests}-%{requests_version}.tar.gz +Source1084: %{chrstnormalizer}-%{chrstnormalizer_version}.tar.gz +Source1085: %{idna}-%{idna_version}.tar.gz +Source1086: %{reqstsoauthlib}-%{reqstsoauthlib_version}.tar.gz +Source1087: %{oauthlib}-%{oauthlib_version}.tar.gz +Source1088: %{ruamelyaml}-%{ruamelyaml_version}.tar.gz +Source1089: %{setuptools}-%{setuptools_version}.tar.gz ## required for installation -Source1115: setuptools_scm-6.3.2.tar.gz -Source1116: packaging-21.2-py3-none-any.whl -Source1117: poetry-core-1.0.7.tar.gz -Source1118: pyparsing-3.0.1.tar.gz -Source1119: tomli-1.0.1.tar.gz +Source1090: setuptools_scm-6.3.2.tar.gz +Source1091: packaging-21.2-py3-none-any.whl +Source1092: poetry-core-1.0.7.tar.gz +Source1093: pyparsing-3.0.1.tar.gz +Source1094: tomli-1.0.1.tar.gz +Source1095: wheel-0.37.0-py2.py3-none-any.whl ### END Patch0: ha-cloud-support-aliyun.patch Patch1: ha-cloud-support-aws.patch Patch2: ha-cloud-support-azure.patch Patch3: ha-cloud-support-google.patch -Patch4: ha-openstack-support.patch -Patch5: bundled-pexpect.patch -Patch6: bundled-suds.patch +Patch4: bundled-pexpect.patch +Patch5: bundled-suds.patch +Patch6: bz2010652-fence_azure_arm-fix-sovereign-cloud-msi-support.patch Patch7: bz2010709-1-fence_amt_ws-fix-or-causing-dead-code.patch Patch8: bz2010709-2-fence_amt_ws-boot-option.patch Patch9: bz2000954-1-configure-fix-virt.patch @@ -232,6 +206,15 @@ Patch15: bz2041933-bz2041935-1-fence_openstack-clouds-openrc.patch Patch16: bz2041933-bz2041935-2-fence_openstack-clouds-openrc.patch Patch17: bz2042496-fence_ibm_vpc-fence_ibm_powervs.patch Patch18: bz2022334-fence_zvmip-add-disable-ssl.patch +Patch19: bz2065114-fence_lpar-refactor.patch +Patch20: bz2072420-1-all-agents-unify-ssl-parameters.patch +Patch21: bz2079889-fence_gce-update.patch +Patch22: bz2081235-fence_ibm_vpc-fix-parameters.patch +Patch23: bz2086559-fence_apc-fence_ilo_moonshot-import-logging.patch +Patch24: bz2072420-2-fence_zvmip-connect-error.patch +Patch25: bz2092385-fence_ibm_vpc-add-proxy-support.patch +Patch26: bz2093216-fence_ibm_powervs-proxy-private-api-servers.patch +Patch27: bz2041933-bz2041935-3-fencing-source_env-dont-process-empty-lines.patch %global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ibm_powervs ibm_vpc ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump kubevirt lpar mpath redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti %ifarch x86_64 @@ -361,6 +344,15 @@ BuildRequires: %{systemd_units} %patch16 -p1 %patch17 -p1 %patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 # prevent compilation of something that won't get used anyway sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac @@ -375,10 +367,7 @@ sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac LIBS="%{_sourcedir}/requirements-*.txt" echo "awscli" >> %{_sourcedir}/requirements-awscli.txt %endif -%ifarch ppc64le -LIBS="%{_sourcedir}/requirements-openstack.txt %{_sourcedir}/requirements-common.txt" -%endif -%ifnarch x86_64 ppc64le +%ifnarch x86_64 LIBS="%{_sourcedir}/requirements-common.txt" %endif for x in $LIBS; do @@ -395,7 +384,7 @@ sed -i -e "/^import awscli.clidriver/isys.path.insert(0, '/usr/lib/%{name}/suppo %endif ./autogen.sh -%{configure} --disable-libvirt-qmf-plugin PYTHONPATH="support/aliyun:support/aws:support/azure:support/google:support/openstack:support/common" --with-agents='%{supportedagents} %{testagents}' +%{configure} --disable-libvirt-qmf-plugin PYTHONPATH="support/aliyun:support/aws:support/azure:support/google:support/common" --with-agents='%{supportedagents} %{testagents}' CFLAGS="$(echo '%{optflags}')" make %{_smp_mflags} %install @@ -581,45 +570,9 @@ Support libraries for Fence Agents. %files -n ha-cloud-support %dir %{_usr}/lib/%{name} %{_usr}/lib/%{name}/support -%exclude %{_usr}/lib/%{name}/support/openstack %exclude %{_usr}/lib/%{name}/support/common %endif -%ifarch x86_64 ppc64le -%package -n ha-openstack-support -License: GPLv2+ and LGPLv2+ -Summary: Support libraries for OpenStack agents -Provides: bundled(python-PyYAML) = 5.1 -Provides: bundled(python-charset-normalizer) = 2.0.4 -Provides: bundled(python-debtcollector) = 2.2.0 -Provides: bundled(python-idna) = 3.2 -Provides: bundled(python-iso8601) = 0.1.16 -Provides: bundled(python-keystoneauth1) = 4.3.1 -Provides: bundled(python-msgpack) = 1.0.2 -Provides: bundled(python-netaddr) = 0.8.0 -Provides: bundled(python-netifaces) = 0.11.0 -Provides: bundled(python-oslo-config) = 8.7.1 -Provides: bundled(python-oslo-i18n) = 5.0.1 -Provides: bundled(python-oslo-serialization) = 4.2.0 -Provides: bundled(python-oslo-utils) = 4.10.0 -Provides: bundled(python-os-service-types) = 1.7.0 -Provides: bundled(python-packaging) = 21.0 -Provides: bundled(python-pbr) = 5.6.0 -Provides: bundled(python-prettytable) = 2.2.0 -Provides: bundled(python-keystoneclient) = 4.2.0 -Provides: bundled(python-novaclient) = 17.5.0 -Provides: bundled(python-requests) = 2.26.0 -Provides: bundled(python-rfc3986) = 1.5.0 -Provides: bundled(python-stevedore) = 3.4.0 -Provides: bundled(python-wcwidth) = 0.2.5 -Provides: bundled(python-wrapt) = 1.12.1 -%description -n ha-openstack-support -Support libraries for Fence Agents. -%files -n ha-openstack-support -%dir %{_usr}/lib/%{name} -%{_usr}/lib/%{name}/support/openstack -%endif - %package all License: GPLv2+ and LGPLv2+ and ASL 2.0 Summary: Set of unified programs capable of host isolation ("fencing") @@ -822,7 +775,7 @@ Requires: python3-requests Requires: python-requests %endif Requires: fence-agents-common = %{version}-%{release} -Requires: ha-openstack-support = %{version}-%{release} +Obsoletes: ha-openstack-support <= %{version}-%{release} %description compute Fence agent for Nova compute nodes. %files compute @@ -1198,7 +1151,7 @@ Requires: python3-requests Requires: python-requests %endif Requires: fence-agents-common = %{version}-%{release} -Requires: ha-openstack-support = %{version}-%{release} +Obsoletes: ha-openstack-support <= %{version}-%{release} %description openstack Fence agent for OpenStack's Nova service. %files openstack @@ -1452,9 +1405,49 @@ are located on corosync cluster nodes. %endif %changelog -* Wed Mar 9 2022 Oyvind Albrigtsen - 4.10.0-20 +* Tue Aug 16 2022 Oyvind Albrigtsen - 4.10.0-30 +- fence_openstack: add support for reading config from clouds.yaml + and openrc + Resolves: rhbz#2041933, rhbz#2041935 + +* Wed Jun 22 2022 Oyvind Albrigtsen - 4.10.0-27 +- fence_ibm_powervs: add support for proxy, private API servers and + get token via API key + Resolves: rhbz#2093216 + +* Wed Jun 1 2022 Oyvind Albrigtsen - 4.10.0-26 +- fence_ibm_vpc: add proxy support + Resolves: rhbz#2092385 + +* Tue May 31 2022 Oyvind Albrigtsen - 4.10.0-25 +- all agents: unify ssl parameters to avoid having to use --ssl when + using --ssl-secure/--ssl-insecure for some agents + Resolves: rhbz#2072420 + +* Tue May 17 2022 Oyvind Albrigtsen - 4.10.0-24 +- fence_apc/fence_ilo_moonshot: add missing "import logging" + Resolves: rhbz#2086559 + +* Thu May 5 2022 Oyvind Albrigtsen - 4.10.0-23 +- fence_ibm_vpc: remove unused instance parameter and make limit + optional + Resolves: rhbz#2081235 + +* Fri Apr 29 2022 Oyvind Albrigtsen - 4.10.0-22 +- fence_gce: update fence agent + Resolves: rhbz#2079889 + +* Wed Apr 6 2022 Oyvind Albrigtsen - 4.10.0-21 +- fence_lpar: refactor to avoid duplicate code + Resolves: rhbz#2065114 + +* Wed Mar 30 2022 Oyvind Albrigtsen - 4.10.0-20 +- fence_azure_arm: fix sovereign cloud and MSI support + Resolves: rhbz#2010652 + +* Mon Mar 7 2022 Oyvind Albrigtsen - 4.10.0-19 - fence_ibm_vpc: new fence agent - Resolves: rhbz#2060562 + Resolves: rhbz#2061321 * Fri Feb 11 2022 Oyvind Albrigtsen - 4.10.0-18 - fence_zvmip: add SSL/TLS support @@ -1464,11 +1457,6 @@ are located on corosync cluster nodes. - fence_ibm_powervs: new fence agent Resolves: rhbz#2042496 -* Wed Jan 19 2022 Oyvind Albrigtsen - 4.10.0-16 -- fence_openstack: add support for reading config from clouds.yaml - and openrc - Resolves: rhbz#2041933, rhbz#2041935 - * Mon Jan 17 2022 Oyvind Albrigtsen - 4.10.0-15 - fence_kubevirt: new fence agent Resolves: rhbz#2000954