diff --git a/.gitignore b/.gitignore index 149f560..60be2e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,14 @@ SOURCES/HAM-logo.png -SOURCES/backports-3.9.1.gem -SOURCES/ethon-0.10.1.gem -SOURCES/ffi-1.9.18.gem +SOURCES/backports-3.11.3.gem +SOURCES/ethon-0.11.0.gem +SOURCES/ffi-1.9.25.gem SOURCES/mock-1.0.1.tar.gz -SOURCES/multi_json-1.12.2.gem +SOURCES/multi_json-1.13.1.gem SOURCES/open4-1.3.4.gem SOURCES/orderedhash-0.0.6.gem -SOURCES/pcs-0.9.162.tar.gz +SOURCES/pcs-0.9.165.tar.gz SOURCES/pyagentx-0.4.pcs.1.tar.gz -SOURCES/rack-1.6.4.gem +SOURCES/rack-1.6.10.gem SOURCES/rack-protection-1.5.5.gem SOURCES/rack-test-0.7.0.gem SOURCES/rpam-ruby19-1.2.1.gem diff --git a/.pcs.metadata b/.pcs.metadata index 8920f4a..9e93a85 100644 --- a/.pcs.metadata +++ b/.pcs.metadata @@ -1,14 +1,14 @@ 80dc7788a3468fb7dd362a4b8bedd9efb373de89 SOURCES/HAM-logo.png -016e62f4967d7d5706bb3c2fce0dd0c004067151 SOURCES/backports-3.9.1.gem -0e362edc1035fa4adc3e52fcc27d15e796e6e9cf SOURCES/ethon-0.10.1.gem -2d92e5efb7753c02d277cba9ad333bb9d51998b0 SOURCES/ffi-1.9.18.gem +b8887abb18c0435eb8d4c9535e5619f7f6a458ec SOURCES/backports-3.11.3.gem +3c921ceeb2847be8cfa25704be74923e233786bd SOURCES/ethon-0.11.0.gem +86fa011857f977254ccf39f507587310f9ade768 SOURCES/ffi-1.9.25.gem baa3446eb63557a24c4522dc5a61cfad082fa395 SOURCES/mock-1.0.1.tar.gz -f4d122fe287c5199040abbcd24c8082e1b0cdf93 SOURCES/multi_json-1.12.2.gem +ff6e0965061cb6f604ee4d87a2cf96a2917f9f88 SOURCES/multi_json-1.13.1.gem 41a7fe9f8e3e02da5ae76c821b89c5b376a97746 SOURCES/open4-1.3.4.gem 709cc95025009e5d221e37cb0777e98582146809 SOURCES/orderedhash-0.0.6.gem -c088d3046113a6f2a6aed22fd1e1fb3daf43b5b5 SOURCES/pcs-0.9.162.tar.gz +3fde33fc0fceb5b251391011b3f2e059d64e0386 SOURCES/pcs-0.9.165.tar.gz 276a92c6d679a71bd0daaf12cb7b3616f1a89b72 SOURCES/pyagentx-0.4.pcs.1.tar.gz -0a1eea6d7bb903d8c075688534480e87d4151470 SOURCES/rack-1.6.4.gem +220afc472c53e0e0a0662c0dd6d4e74158f1845c SOURCES/rack-1.6.10.gem f80ea6672253a90fa031db0c1e2e1fe056582118 SOURCES/rack-protection-1.5.5.gem 3f41699c1c19ff2e2353583afa70799ced351a36 SOURCES/rack-test-0.7.0.gem a90e5a60d99445404a3c29a66d953a5e9918976d SOURCES/rpam-ruby19-1.2.1.gem diff --git a/SOURCES/adapt-working-with-gems-to-rhel-7.patch b/SOURCES/adapt-working-with-gems-to-rhel-7.patch new file mode 100644 index 0000000..a75940b --- /dev/null +++ b/SOURCES/adapt-working-with-gems-to-rhel-7.patch @@ -0,0 +1,68 @@ +From 8d958e9f63698bd05b19213ddbf71b57cb228135 Mon Sep 17 00:00:00 2001 +From: Ivan Devat +Date: Tue, 24 May 2016 07:26:15 +0200 +Subject: [PATCH 3/5] adapt working with gems to rhel 7 + +--- + pcsd/Gemfile | 1 - + pcsd/Gemfile.lock | 2 -- + pcsd/Makefile | 5 +---- + 3 files changed, 1 insertion(+), 7 deletions(-) + +diff --git a/pcsd/Gemfile b/pcsd/Gemfile +index 6418fd41..3598f533 100644 +--- a/pcsd/Gemfile ++++ b/pcsd/Gemfile +@@ -8,7 +8,6 @@ gem 'tilt' + gem 'rack-test' + gem 'backports' + gem 'rpam-ruby19' +-gem 'json' + gem 'multi_json' + gem 'open4' + gem 'ffi' +diff --git a/pcsd/Gemfile.lock b/pcsd/Gemfile.lock +index 4b78bba6..137086ca 100644 +--- a/pcsd/Gemfile.lock ++++ b/pcsd/Gemfile.lock +@@ -4,7 +4,6 @@ GEM + backports (3.11.3) + ethon (0.11.0) + ffi (1.9.25) +- json (2.1.0) + multi_json (1.13.1) + open4 (1.3.4) + rack (1.6.10) +@@ -33,7 +32,6 @@ DEPENDENCIES + backports + ethon + ffi +- json + multi_json + open4 + rack +diff --git a/pcsd/Makefile b/pcsd/Makefile +index 21550c5a..642d0c83 100644 +--- a/pcsd/Makefile ++++ b/pcsd/Makefile +@@ -1,7 +1,7 @@ + FFI_VERSION="1.9.25" + FFI_C_DIR=vendor/bundle/ruby/gems/ffi-${FFI_VERSION}/ext/ffi_c + +-build_gems: get_gems ++build_gems: + bundle install --local --deployment + #ffi makes symlink with absolute path. Let's change it to relative path. + for fname in `ls ${FFI_C_DIR}/libffi-*/include/ffitarget.h`; do \ +@@ -30,8 +30,5 @@ build_gems_without_bundler: + vendor/cache/tilt-2.0.8.gem \ + -- '--with-ldflags="-Wl,-z,now -Wl,-z,relro"' + +-get_gems: +- bundle package +- + clean: + rm -rfv vendor/ +-- +2.13.6 + diff --git a/SOURCES/bz1367808-01-fix-formating-of-assertion-error-in-snmp.patch b/SOURCES/bz1367808-01-fix-formating-of-assertion-error-in-snmp.patch deleted file mode 100644 index 43aed3b..0000000 --- a/SOURCES/bz1367808-01-fix-formating-of-assertion-error-in-snmp.patch +++ /dev/null @@ -1,27 +0,0 @@ -From b1c3a422b55f27cb6bc7b60b89a0c929eff0a030 Mon Sep 17 00:00:00 2001 -From: Ondrej Mular -Date: Tue, 21 Nov 2017 12:07:43 +0100 -Subject: [PATCH] fix formating of assertion error in snmp - ---- - pcs/snmp/agentx/updater.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/pcs/snmp/agentx/updater.py b/pcs/snmp/agentx/updater.py -index 7ac20ae..c63f96b 100644 ---- a/pcs/snmp/agentx/updater.py -+++ b/pcs/snmp/agentx/updater.py -@@ -82,8 +82,8 @@ def _str_oid_to_oid(sub_tree, str_oid): - sub_tree = _find_oid_in_sub_tree(sub_tree, section) - if sub_tree is None: - raise AssertionError( -- "oid section {0} ({1}) not found in {1} ({2})".format( -- section, str_oid, sub_tree.str_oid -+ "oid section '{0}' ({1}) not found in section '{2}'".format( -+ section, str_oid, oid_list[-1] if len(oid_list) else "." - ) - ) - oid_list.append(str(sub_tree.oid)) --- -1.8.3.1 - diff --git a/SOURCES/bz1367808-02-change-snmp-agent-logfile-path.patch b/SOURCES/bz1367808-02-change-snmp-agent-logfile-path.patch deleted file mode 100644 index 425ca82..0000000 --- a/SOURCES/bz1367808-02-change-snmp-agent-logfile-path.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 771e99602c7920b2473706a8bdf2e8a57e1d2aec Mon Sep 17 00:00:00 2001 -From: Ondrej Mular -Date: Tue, 28 Nov 2017 13:20:16 +0100 -Subject: [PATCH] change snmp agent logfile path - ---- - Makefile | 1 - - pcs/snmp/pcs_snmp_agent.logrotate | 10 ---------- - pcs/snmp/settings.py | 2 +- - pcsd/pcsd.logrotate | 2 +- - 4 files changed, 2 insertions(+), 13 deletions(-) - delete mode 100644 pcs/snmp/pcs_snmp_agent.logrotate - -diff --git a/Makefile b/Makefile -index 04cd62a..5d4aed8 100644 ---- a/Makefile -+++ b/Makefile -@@ -129,7 +129,6 @@ install: install_bundled_libs - install -d ${SNMP_MIB_DIR_FULL} - install -m 644 pcs/snmp/mibs/PCMK-PCS*-MIB.txt ${SNMP_MIB_DIR_FULL} - install -m 644 -D pcs/snmp/pcs_snmp_agent.conf ${DESTDIR}/etc/sysconfig/pcs_snmp_agent -- install -m 644 -D pcs/snmp/pcs_snmp_agent.logrotate ${DESTDIR}/etc/logrotate.d/pcs_snmp_agent - install -m 644 -D pcs/snmp/pcs_snmp_agent.8 ${DESTDIR}/${MANDIR}/man8/pcs_snmp_agent.8 - ifeq ($(IS_SYSTEMCTL),true) - install -d ${DESTDIR}/${systemddir}/system/ -diff --git a/pcs/snmp/pcs_snmp_agent.logrotate b/pcs/snmp/pcs_snmp_agent.logrotate -deleted file mode 100644 -index a53c21f..0000000 ---- a/pcs/snmp/pcs_snmp_agent.logrotate -+++ /dev/null -@@ -1,10 +0,0 @@ --/var/log/pcs/snmp/pcs_snmp_agent.log { -- rotate 5 -- weekly -- missingok -- notifempty -- compress -- delaycompress -- copytruncate -- create 0600 root root --} -diff --git a/pcs/snmp/settings.py b/pcs/snmp/settings.py -index 0559446..5f054ae 100644 ---- a/pcs/snmp/settings.py -+++ b/pcs/snmp/settings.py -@@ -4,7 +4,7 @@ from __future__ import ( - print_function, - ) - --LOG_FILE = "/var/log/pcs/pcs_snmp_agent.log" -+LOG_FILE = "/var/log/pcsd/pcs_snmp_agent.log" - ENTERPRISES_OID = "1.3.6.1.4.1" - PACEMAKER_OID = ENTERPRISES_OID + ".32723" - PCS_OID = PACEMAKER_OID + ".100" -diff --git a/pcsd/pcsd.logrotate b/pcsd/pcsd.logrotate -index 36d2529..d105cff 100644 ---- a/pcsd/pcsd.logrotate -+++ b/pcsd/pcsd.logrotate -@@ -1,4 +1,4 @@ --/var/log/pcsd/pcsd.log { -+/var/log/pcsd/*.log { - rotate 5 - weekly - missingok --- -1.8.3.1 - diff --git a/SOURCES/bz1415197-01-fix-pcs-cluster-auth.patch b/SOURCES/bz1415197-01-fix-pcs-cluster-auth.patch deleted file mode 100644 index c7d6aae..0000000 --- a/SOURCES/bz1415197-01-fix-pcs-cluster-auth.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 9ec76750dc457e0a445fd43bbc172ab3c3de1a23 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Thu, 1 Feb 2018 11:10:27 +0100 -Subject: [PATCH 1/2] fix 'pcs cluster auth' - ---- - pcsd/cfgsync.rb | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/pcsd/cfgsync.rb b/pcsd/cfgsync.rb -index 14b55736..36ae1abb 100644 ---- a/pcsd/cfgsync.rb -+++ b/pcsd/cfgsync.rb -@@ -795,7 +795,7 @@ module Cfgsync - # we run in a cluster so we need to sync the config - publisher = ConfigPublisher.new( - PCSAuth.getSuperuserAuth(), [config_new], nodes, cluster_name, -- new_tokens -+ new_tokens, new_ports - ) - old_configs, node_responses = publisher.publish() - if not old_configs.include?(config_new.class.name) --- -2.13.6 - diff --git a/SOURCES/bz1415197-02-fix-pcs-cluster-auth.patch b/SOURCES/bz1415197-02-fix-pcs-cluster-auth.patch deleted file mode 100644 index 2483ab8..0000000 --- a/SOURCES/bz1415197-02-fix-pcs-cluster-auth.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 4c2dc964999f57395f377d44594324e5ae3df1b0 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Thu, 1 Feb 2018 13:13:23 +0100 -Subject: [PATCH 2/2] fix 'pcs cluster auth' - ---- - pcsd/pcs.rb | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/pcsd/pcs.rb b/pcsd/pcs.rb -index 68d2e7ed..43f58f22 100644 ---- a/pcsd/pcs.rb -+++ b/pcsd/pcs.rb -@@ -1247,7 +1247,7 @@ def pcs_auth(auth_user, nodes, username, password, force=false, local=true) - auth_responses.each { |node, response| - if 'ok' == response['status'] - new_tokens[node] = response['token'] -- ports[node] = nodes[node] -+ ports[node] = nodes[node] || PCSD_DEFAULT_PORT - end - } - if not new_tokens.empty? --- -2.13.6 - diff --git a/SOURCES/bz1421702-01-gui-allow-forcing-resource-stonith-create-update.patch b/SOURCES/bz1421702-01-gui-allow-forcing-resource-stonith-create-update.patch deleted file mode 100644 index 713b08d..0000000 --- a/SOURCES/bz1421702-01-gui-allow-forcing-resource-stonith-create-update.patch +++ /dev/null @@ -1,114 +0,0 @@ -From bca125ee785104fbffdcf487b22599e3c9980f06 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Tue, 5 Dec 2017 15:10:43 +0100 -Subject: [PATCH] gui: allow forcing resource|stonith create|update - ---- - pcsd/pcsd.rb | 3 +++ - pcsd/public/js/pcsd.js | 39 +++++++++++++++++++++++++-------------- - pcsd/remote.rb | 2 +- - 3 files changed, 29 insertions(+), 15 deletions(-) - -diff --git a/pcsd/pcsd.rb b/pcsd/pcsd.rb -index f97dabc..8f5ad81 100644 ---- a/pcsd/pcsd.rb -+++ b/pcsd/pcsd.rb -@@ -211,6 +211,9 @@ helpers do - if param == "disabled" - meta_options << 'meta' << 'target-role=Stopped' - end -+ if param == "force" and val -+ param_line << "--force" -+ end - } - return param_line + meta_options - end -diff --git a/pcsd/public/js/pcsd.js b/pcsd/public/js/pcsd.js -index b7e9a7a..2956530 100644 ---- a/pcsd/public/js/pcsd.js -+++ b/pcsd/public/js/pcsd.js -@@ -286,9 +286,24 @@ function create_node(form) { - }); - } - -+function create_resource_error_processing(error_message, form, update, stonith) { -+ var message = ( -+ "Unable to " + (update ? "update " : "add ") + name + "\n" + error_message -+ ); -+ if (message.indexOf('--force') == -1) { -+ alert(message); -+ } -+ else { -+ message = message.replace(', use --force to override', ''); -+ if (confirm(message + "\n\nDo you want to force the operation?")) { -+ create_resource(form, update, stonith, true) -+ } -+ } -+} -+ - // If update is set to true we update the resource instead of create it - // if stonith is set to true we update/create a stonith agent --function create_resource(form, update, stonith) { -+function create_resource(form, update, stonith, force) { - var data = {}; - $($(form).serializeArray()).each(function(index, obj) { - data[obj.name] = obj.value; -@@ -303,6 +318,9 @@ function create_resource(form, update, stonith) { - } else { - name = "resource"; - } -+ if (force) { -+ data["force"] = force; -+ } - - ajax_wrapper({ - type: "POST", -@@ -312,7 +330,9 @@ function create_resource(form, update, stonith) { - success: function(returnValue) { - $('input.apply_changes').show(); - if (returnValue["error"] == "true") { -- alert(returnValue["stderr"]); -+ create_resource_error_processing( -+ returnValue["stderr"], form, update, stonith -+ ); - } else { - Pcs.update(); - if (!update) { -@@ -326,18 +346,9 @@ function create_resource(form, update, stonith) { - } - }, - error: function(xhr, status, error) { -- if (update) { -- alert( -- "Unable to update " + name + " " -- + ajax_simple_error(xhr, status, error) -- ); -- } -- else { -- alert( -- "Unable to add " + name + " " -- + ajax_simple_error(xhr, status, error) -- ); -- } -+ create_resource_error_processing( -+ ajax_simple_error(xhr, status, error), form, update, stonith -+ ); - $('input.apply_changes').show(); - } - }); -diff --git a/pcsd/remote.rb b/pcsd/remote.rb -index e1e95a8..518e668 100644 ---- a/pcsd/remote.rb -+++ b/pcsd/remote.rb -@@ -1494,7 +1494,7 @@ def update_resource (params, request, auth_user) - end - resource_group = params[:resource_group] - end -- if params[:resource_type] == "ocf:pacemaker:remote" -+ if params[:resource_type] == "ocf:pacemaker:remote" and not cmd.include?("--force") - # Workaround for Error: this command is not sufficient for create remote - # connection, use 'pcs cluster node add-remote', use --force to override. - # It is not possible to specify meta attributes so we don't need to take --- -1.8.3.1 - diff --git a/SOURCES/bz1458153-01-give-back-orig.-master-behav.-resource-create.patch b/SOURCES/bz1458153-01-give-back-orig.-master-behav.-resource-create.patch index b7f98cd..fb97ff0 100644 --- a/SOURCES/bz1458153-01-give-back-orig.-master-behav.-resource-create.patch +++ b/SOURCES/bz1458153-01-give-back-orig.-master-behav.-resource-create.patch @@ -1,7 +1,7 @@ -From fe7151898fed1b6383a49db26426c3f23c5ff7f2 Mon Sep 17 00:00:00 2001 +From 4d6997edab3c3e478fb0d73e0dc6dc2a924ed664 Mon Sep 17 00:00:00 2001 From: Ivan Devat Date: Mon, 5 Jun 2017 17:13:41 +0200 -Subject: [PATCH] give back orig. --master behav. (resource create) +Subject: [PATCH 1/5] give back orig. --master behav. (resource create) --- pcs/cli/common/parse_args.py | 8 +- @@ -14,7 +14,7 @@ Subject: [PATCH] give back orig. --master behav. (resource create) 7 files changed, 228 insertions(+), 59 deletions(-) diff --git a/pcs/cli/common/parse_args.py b/pcs/cli/common/parse_args.py -index 70b926c0..d3151043 100644 +index 7d6f6006..5c709245 100644 --- a/pcs/cli/common/parse_args.py +++ b/pcs/cli/common/parse_args.py @@ -299,7 +299,13 @@ def upgrade_args(arg_list): @@ -87,7 +87,7 @@ index efe38d0e..900094c9 100644 ], upgrade_args([ diff --git a/pcs/resource.py b/pcs/resource.py -index 082bd9d1..6637f806 100644 +index c605cc6a..cdba2bfd 100644 --- a/pcs/resource.py +++ b/pcs/resource.py @@ -384,6 +384,25 @@ def resource_create(lib, argv, modifiers): @@ -117,7 +117,7 @@ index 082bd9d1..6637f806 100644 defined_options = [opt for opt in parts_sections if opt in parts] if modifiers["group"]: diff --git a/pcs/test/cib_resource/test_create.py b/pcs/test/cib_resource/test_create.py -index cfb2e645..c554ec24 100644 +index 36202e34..e5f9dd4d 100644 --- a/pcs/test/cib_resource/test_create.py +++ b/pcs/test/cib_resource/test_create.py @@ -233,7 +233,7 @@ class Success(ResourceTest): @@ -378,7 +378,7 @@ index cfb2e645..c554ec24 100644 , """ -@@ -1041,7 +1154,7 @@ class FailOrWarn(ResourceTest): +@@ -1043,7 +1156,7 @@ class FailOrWarn(ResourceTest): def test_error_master_clone_combination(self): self.assert_pcs_fail( "resource create R ocf:heartbeat:Dummy --no-default-ops --clone" @@ -387,7 +387,7 @@ index cfb2e645..c554ec24 100644 , "Error: you can specify only one of clone, master, bundle or" " --group\n" -@@ -1049,7 +1162,7 @@ class FailOrWarn(ResourceTest): +@@ -1051,7 +1164,7 @@ class FailOrWarn(ResourceTest): def test_error_master_group_combination(self): self.assert_pcs_fail( @@ -396,7 +396,7 @@ index cfb2e645..c554ec24 100644 " --group G" , "Error: you can specify only one of clone, master, bundle or" -@@ -1067,7 +1180,7 @@ class FailOrWarn(ResourceTest): +@@ -1069,7 +1182,7 @@ class FailOrWarn(ResourceTest): def test_error_bundle_master_combination(self): self.assert_pcs_fail( @@ -406,7 +406,7 @@ index cfb2e645..c554ec24 100644 , "Error: you can specify only one of clone, master, bundle or" diff --git a/pcs/test/test_constraints.py b/pcs/test/test_constraints.py -index 9f0bc5d6..f5973410 100644 +index 07226acf..d17230ac 100644 --- a/pcs/test/test_constraints.py +++ b/pcs/test/test_constraints.py @@ -346,43 +346,43 @@ Ticket Constraints: @@ -500,10 +500,10 @@ index 9f0bc5d6..f5973410 100644 ac(output, """\ Warning: changing a monitor operation interval from 10 to 11 to make the operation unique diff --git a/pcs/test/test_resource.py b/pcs/test/test_resource.py -index bd596f64..d8f68c12 100644 +index 59432999..7828efb4 100644 --- a/pcs/test/test_resource.py +++ b/pcs/test/test_resource.py -@@ -2826,7 +2826,7 @@ Ticket Constraints: +@@ -2840,7 +2840,7 @@ Ticket Constraints: output, returnVal = pcs( temp_cib, @@ -512,7 +512,7 @@ index bd596f64..d8f68c12 100644 ) assert returnVal == 0 assert output == "", [output] -@@ -2919,7 +2919,7 @@ Warning: changing a monitor operation interval from 10 to 11 to make the operati +@@ -2933,7 +2933,7 @@ Warning: changing a monitor operation interval from 10 to 11 to make the operati ac(o,"") assert r == 0 @@ -521,7 +521,7 @@ index bd596f64..d8f68c12 100644 ac(o,"") assert r == 0 -@@ -3133,7 +3133,7 @@ Warning: changing a monitor operation interval from 10 to 11 to make the operati +@@ -3147,7 +3147,7 @@ Warning: changing a monitor operation interval from 10 to 11 to make the operati output, returnVal = pcs( temp_cib, @@ -530,7 +530,7 @@ index bd596f64..d8f68c12 100644 ) ac(output, "") self.assertEqual(0, returnVal) -@@ -3727,7 +3727,7 @@ Error: Cannot remove more than one resource from cloned group +@@ -3741,7 +3741,7 @@ Error: Cannot remove more than one resource from cloned group # However those test the pcs library. I'm leaving these tests here to # test the cli part for now. self.assert_pcs_success( @@ -539,7 +539,7 @@ index bd596f64..d8f68c12 100644 "Warning: changing a monitor operation interval from 10 to 11 to make the operation unique\n" ) -@@ -4761,7 +4761,7 @@ class CloneMasterUpdate(unittest.TestCase, AssertPcsMixin): +@@ -4775,7 +4775,7 @@ class CloneMasterUpdate(unittest.TestCase, AssertPcsMixin): def test_no_op_allowed_in_master_update(self): self.assert_pcs_success( @@ -549,13 +549,13 @@ index bd596f64..d8f68c12 100644 self.assert_pcs_success("resource show dummy-master", outdent( """\ diff --git a/pcs/utils.py b/pcs/utils.py -index 5b608239..9b46810f 100644 +index 8a989f52..343a611b 100644 --- a/pcs/utils.py +++ b/pcs/utils.py -@@ -2861,6 +2861,13 @@ def get_modificators(): - "start": "--start" in pcs_options, +@@ -2904,6 +2904,13 @@ def get_modifiers(): "wait": pcs_options.get("--wait", False), "watchdog": pcs_options.get("--watchdog", []), + "no_watchdog_validation": "--no-watchdog-validation" in pcs_options, + + #This is for `pcs resource create`. Fix of the bug + #https://bugzilla.redhat.com/show_bug.cgi?id=1378107 diff --git a/SOURCES/bz1459503-01-OSP-workarounds-not-compatible-wi.patch b/SOURCES/bz1459503-01-OSP-workarounds-not-compatible-wi.patch index 9a7a010..b3e4b3f 100644 --- a/SOURCES/bz1459503-01-OSP-workarounds-not-compatible-wi.patch +++ b/SOURCES/bz1459503-01-OSP-workarounds-not-compatible-wi.patch @@ -1,7 +1,7 @@ -From b5f98fed9903bc6c4e30056aa99f3be6fcb68917 Mon Sep 17 00:00:00 2001 +From bbb137919a73cffdb635ed77d7f2b2e35f2cd056 Mon Sep 17 00:00:00 2001 From: Ivan Devat Date: Wed, 7 Jun 2017 14:36:05 +0200 -Subject: [PATCH] squash bz1459503 OSP workarounds not compatible wi +Subject: [PATCH 2/5] squash bz1459503 OSP workarounds not compatible wi reuse existing pcmk authkey during setup @@ -14,10 +14,10 @@ show only warn if `resource create` creates remote 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/pcs/cluster.py b/pcs/cluster.py -index b66bec78..a3cc74c6 100644 +index e8c94ab8..c2af8a8f 100644 --- a/pcs/cluster.py +++ b/pcs/cluster.py -@@ -501,13 +501,21 @@ def cluster_setup(argv): +@@ -517,13 +517,21 @@ def cluster_setup(argv): print("Destroying cluster on nodes: {0}...".format( ", ".join(primary_addr_list) )) @@ -41,10 +41,10 @@ index b66bec78..a3cc74c6 100644 if modifiers["encryption"] == "1": file_definitions.update( diff --git a/pcs/lib/commands/resource.py b/pcs/lib/commands/resource.py -index 8cda3102..cb45771f 100644 +index 5637113c..6d59e8f9 100644 --- a/pcs/lib/commands/resource.py +++ b/pcs/lib/commands/resource.py -@@ -67,7 +67,8 @@ def _validate_remote_connection( +@@ -76,7 +76,8 @@ def _validate_remote_connection( report_list.append( reports.get_problem_creator( report_codes.FORCE_NOT_SUITABLE_COMMAND, @@ -54,7 +54,7 @@ index 8cda3102..cb45771f 100644 )(reports.use_command_node_add_remote) ) -@@ -97,7 +98,8 @@ def _validate_guest_change( +@@ -106,7 +107,8 @@ def _validate_guest_change( report_list.append( reports.get_problem_creator( report_codes.FORCE_NOT_SUITABLE_COMMAND, @@ -65,10 +65,10 @@ index 8cda3102..cb45771f 100644 ) diff --git a/pcs/test/cib_resource/test_create.py b/pcs/test/cib_resource/test_create.py -index c554ec24..282ce1c5 100644 +index e5f9dd4d..8a445f09 100644 --- a/pcs/test/cib_resource/test_create.py +++ b/pcs/test/cib_resource/test_create.py -@@ -1581,11 +1581,10 @@ class FailOrWarnGroup(ResourceTest): +@@ -1583,11 +1583,10 @@ class FailOrWarnGroup(ResourceTest): ) def test_fail_when_on_pacemaker_remote_attempt(self): @@ -83,7 +83,7 @@ index c554ec24..282ce1c5 100644 ) def test_warn_when_on_pacemaker_remote_attempt(self): -@@ -1685,10 +1684,10 @@ class FailOrWarnGroup(ResourceTest): +@@ -1687,10 +1686,10 @@ class FailOrWarnGroup(ResourceTest): ) def test_fail_when_on_pacemaker_remote_guest_attempt(self): @@ -98,10 +98,10 @@ index c554ec24..282ce1c5 100644 def test_warn_when_on_pacemaker_remote_guest_attempt(self): diff --git a/pcs/test/test_resource.py b/pcs/test/test_resource.py -index d8f68c12..eac7eb04 100644 +index 7828efb4..8397df76 100644 --- a/pcs/test/test_resource.py +++ b/pcs/test/test_resource.py -@@ -5110,10 +5110,10 @@ class ResourceUpdateSpcialChecks(unittest.TestCase, AssertPcsMixin): +@@ -5126,10 +5126,10 @@ class ResourceUpdateSpcialChecks(unittest.TestCase, AssertPcsMixin): self.assert_pcs_success( "resource create R ocf:heartbeat:Dummy", ) @@ -115,7 +115,7 @@ index d8f68c12..eac7eb04 100644 ) def test_update_warn_on_pacemaker_guest_attempt(self): self.assert_pcs_success( -@@ -5132,10 +5132,10 @@ class ResourceUpdateSpcialChecks(unittest.TestCase, AssertPcsMixin): +@@ -5148,10 +5148,10 @@ class ResourceUpdateSpcialChecks(unittest.TestCase, AssertPcsMixin): "Warning: this command is not sufficient for creating a guest node," " use 'pcs cluster node add-guest'\n" ) @@ -129,7 +129,7 @@ index d8f68c12..eac7eb04 100644 ) def test_update_warn_on_pacemaker_guest_attempt_remove(self): -@@ -5156,10 +5156,10 @@ class ResourceUpdateSpcialChecks(unittest.TestCase, AssertPcsMixin): +@@ -5172,10 +5172,10 @@ class ResourceUpdateSpcialChecks(unittest.TestCase, AssertPcsMixin): self.assert_pcs_success( "resource create R ocf:heartbeat:Dummy", ) @@ -143,7 +143,7 @@ index d8f68c12..eac7eb04 100644 ) def test_meta_warn_on_pacemaker_guest_attempt(self): -@@ -5180,10 +5180,10 @@ class ResourceUpdateSpcialChecks(unittest.TestCase, AssertPcsMixin): +@@ -5196,10 +5196,10 @@ class ResourceUpdateSpcialChecks(unittest.TestCase, AssertPcsMixin): "Warning: this command is not sufficient for creating a guest node," " use 'pcs cluster node add-guest'\n" ) diff --git a/SOURCES/bz1462248-01-fix-error-for-an-inaccessible-resource-in-a-bundle.patch b/SOURCES/bz1462248-01-fix-error-for-an-inaccessible-resource-in-a-bundle.patch new file mode 100644 index 0000000..d90d09b --- /dev/null +++ b/SOURCES/bz1462248-01-fix-error-for-an-inaccessible-resource-in-a-bundle.patch @@ -0,0 +1,62 @@ +From 8811ee0493b956207f3336e9e0eb1395a530af8f Mon Sep 17 00:00:00 2001 +From: Ivan Devat +Date: Mon, 6 Aug 2018 08:43:47 +0200 +Subject: [PATCH] fix error for an inaccessible resource in a bundle + +--- + pcs/cli/common/console_report.py | 6 +++--- + pcs/cli/common/test/test_console_report.py | 6 +++--- + pcs/resource.py | 1 + + 3 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/pcs/cli/common/console_report.py b/pcs/cli/common/console_report.py +index f2cee05e..06ea8f72 100644 +--- a/pcs/cli/common/console_report.py ++++ b/pcs/cli/common/console_report.py +@@ -1434,8 +1434,8 @@ CODE_TO_MESSAGE_BUILDER_MAP = { + , + codes.RESOURCE_IN_BUNDLE_NOT_ACCESSIBLE: lambda info: + ( +- "Resource '{resource_id}' will not be accessible by the cluster " +- "inside bundle '{bundle_id}'. At least one of bundle options " +- "'control-port' or 'ip-range-start' has to be specified." ++ "Resource '{inner_resource_id}' will not be accessible by the " ++ "cluster inside bundle '{bundle_id}', at least one of bundle " ++ "options 'control-port' or 'ip-range-start' has to be specified" + ).format(**info) + } +diff --git a/pcs/cli/common/test/test_console_report.py b/pcs/cli/common/test/test_console_report.py +index dee633ad..5fe49466 100644 +--- a/pcs/cli/common/test/test_console_report.py ++++ b/pcs/cli/common/test/test_console_report.py +@@ -2126,12 +2126,12 @@ class ResourceInBundleNotAccessible(NameBuildTest): + self.assert_message_from_info( + ( + "Resource 'resourceA' will not be accessible by the cluster " +- "inside bundle 'bundleA'. At least one of bundle options " +- "'control-port' or 'ip-range-start' has to be specified." ++ "inside bundle 'bundleA', at least one of bundle options " ++ "'control-port' or 'ip-range-start' has to be specified" + ), + dict( + bundle_id="bundleA", +- resource_id="resourceA", ++ inner_resource_id="resourceA", + ) + ) + +diff --git a/pcs/resource.py b/pcs/resource.py +index 001bad50..c605cc6a 100644 +--- a/pcs/resource.py ++++ b/pcs/resource.py +@@ -439,6 +439,7 @@ def resource_create(lib, argv, modifiers): + **settings + ) + elif "bundle" in parts: ++ settings["allow_not_accessible_resource"] = modifiers["force"] + lib.resource.create_into_bundle( + ra_id, ra_type, parts["op"], + parts["meta"], +-- +2.13.6 + diff --git a/SOURCES/bz1464781-01-fix-exit-code-when-adding-a-remote-or-guest-node.patch b/SOURCES/bz1464781-01-fix-exit-code-when-adding-a-remote-or-guest-node.patch deleted file mode 100644 index a964969..0000000 --- a/SOURCES/bz1464781-01-fix-exit-code-when-adding-a-remote-or-guest-node.patch +++ /dev/null @@ -1,39 +0,0 @@ -From f45f7cd9feffcdba68c880b0a28fb7ebde94ad58 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Wed, 3 Jan 2018 17:21:29 +0100 -Subject: [PATCH] fix exit code when adding a remote or guest node - ---- - pcs/cli/common/reports.py | 2 +- - pcs/cluster.py | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/pcs/cli/common/reports.py b/pcs/cli/common/reports.py -index 5fd39cb..f96db73 100644 ---- a/pcs/cli/common/reports.py -+++ b/pcs/cli/common/reports.py -@@ -130,7 +130,7 @@ def process_library_reports(report_item_list): - report_item_list list of ReportItem - """ - if not report_item_list: -- error("Errors have occurred, therefore pcs is unable to continue") -+ raise error("Errors have occurred, therefore pcs is unable to continue") - - critical_error = False - for report_item in report_item_list: -diff --git a/pcs/cluster.py b/pcs/cluster.py -index a330164..b66bec7 100644 ---- a/pcs/cluster.py -+++ b/pcs/cluster.py -@@ -209,7 +209,7 @@ def cluster_cmd(argv): - utils.get_modificators() - ) - except LibraryError as e: -- utils.process_library_reports(e.args) -+ process_library_reports(e.args) - except CmdLineInputError as e: - utils.exit_on_cmdline_input_errror( - e, "cluster", "node " + argv[0] --- -1.8.3.1 - diff --git a/SOURCES/bz1475318-01-rfe-validate-nodes-watchdog-device-by-using-sbd.patch b/SOURCES/bz1475318-01-rfe-validate-nodes-watchdog-device-by-using-sbd.patch new file mode 100644 index 0000000..0c73465 --- /dev/null +++ b/SOURCES/bz1475318-01-rfe-validate-nodes-watchdog-device-by-using-sbd.patch @@ -0,0 +1,111 @@ +From 2e5005b822b1dab3d074361f46607af3bd696b71 Mon Sep 17 00:00:00 2001 +From: Ivan Devat +Date: Mon, 6 Aug 2018 08:43:47 +0200 +Subject: [PATCH] squash bz1475318 RFE: Validate node's watchdog dev + +9d95b73a1b22 do not connect stdin of subprocess to pcs's stdin + +7607976d478e fix tests +--- + pcs/lib/external.py | 10 +++++++++- + pcs/test/test_lib_external.py | 8 ++++---- + pcs/utils.py | 8 +++++++- + 3 files changed, 20 insertions(+), 6 deletions(-) + +diff --git a/pcs/lib/external.py b/pcs/lib/external.py +index 5507543f..fe17a864 100644 +--- a/pcs/lib/external.py ++++ b/pcs/lib/external.py +@@ -25,6 +25,12 @@ try: + except ImportError: + # python3 + from urllib.parse import urlencode as urllib_urlencode ++try: ++ # python 3 ++ from subprocess import DEVNULL ++except ImportError: ++ # python 2 ++ DEVNULL = open(os.devnull, "r") + + from pcs import settings + from pcs.common import pcs_pycurl as pycurl +@@ -401,7 +407,9 @@ class CommandRunner(object): + process = subprocess.Popen( + args, + # Some commands react differently if they get anything via stdin +- stdin=(subprocess.PIPE if stdin_string is not None else None), ++ stdin=( ++ subprocess.PIPE if stdin_string is not None else DEVNULL ++ ), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + preexec_fn=( +diff --git a/pcs/test/test_lib_external.py b/pcs/test/test_lib_external.py +index b249c47a..85c52a18 100644 +--- a/pcs/test/test_lib_external.py ++++ b/pcs/test/test_lib_external.py +@@ -74,7 +74,7 @@ class CommandRunnerTest(TestCase): + self.assert_popen_called_with( + mock_popen, + command, +- {"env": {}, "stdin": None,} ++ {"env": {}, "stdin": lib.DEVNULL,} + ) + logger_calls = [ + mock.call("Running: {0}\nEnvironment:".format(command_str)), +@@ -158,7 +158,7 @@ class CommandRunnerTest(TestCase): + self.assert_popen_called_with( + mock_popen, + command, +- {"env": {"a": "a", "b": "B", "c": "{C}"}, "stdin": None,} ++ {"env": {"a": "a", "b": "B", "c": "{C}"}, "stdin": lib.DEVNULL,} + ) + logger_calls = [ + mock.call( +@@ -327,7 +327,7 @@ class CommandRunnerTest(TestCase): + self.assert_popen_called_with( + mock_popen, + command, +- {"env": {}, "stdin": None,} ++ {"env": {}, "stdin": lib.DEVNULL,} + ) + logger_calls = [ + mock.call("Running: {0}\nEnvironment:".format(command_str)), +@@ -376,7 +376,7 @@ class CommandRunnerTest(TestCase): + self.assert_popen_called_with( + mock_popen, + command, +- {"env": {}, "stdin": None,} ++ {"env": {}, "stdin": lib.DEVNULL,} + ) + logger_calls = [ + mock.call("Running: {0}\nEnvironment:".format(command_str)), +diff --git a/pcs/utils.py b/pcs/utils.py +index eb02ca34..347ad73e 100644 +--- a/pcs/utils.py ++++ b/pcs/utils.py +@@ -86,6 +86,12 @@ try: + except ImportError: + # python3 + from urllib.parse import urlencode as urllib_urlencode ++try: ++ # python 3 ++ from subprocess import DEVNULL ++except ImportError: ++ # python 2 ++ DEVNULL = open(os.devnull, "r") + + + PYTHON2 = (sys.version_info.major == 2) +@@ -1035,7 +1041,7 @@ def run( + if string_for_stdin != None: + stdin_pipe = subprocess.PIPE + else: +- stdin_pipe = None ++ stdin_pipe = DEVNULL + + p = subprocess.Popen( + args, +-- +2.13.6 + diff --git a/SOURCES/bz1475318-02-rfe-validate-nodes-watchdog-device-by-using-sbd.patch b/SOURCES/bz1475318-02-rfe-validate-nodes-watchdog-device-by-using-sbd.patch new file mode 100644 index 0000000..6aaf42d --- /dev/null +++ b/SOURCES/bz1475318-02-rfe-validate-nodes-watchdog-device-by-using-sbd.patch @@ -0,0 +1,86 @@ +From e66477b89b6a0ffbb9220c1a384c2a283dddcf17 Mon Sep 17 00:00:00 2001 +From: Ondrej Mular +Date: Thu, 23 Aug 2018 14:49:05 +0200 +Subject: [PATCH] squash bz1475318 RFE: Validate node's watchdog dev + +6ae0b56ea1d9 fix watchdog device test error message + +3685516072c8 Mark all watchdogs listed by SBD as supported +--- + pcs/lib/sbd.py | 6 +++--- + pcs/stonith.py | 22 +++++----------------- + pcsd/remote.rb | 5 ++++- + 3 files changed, 12 insertions(+), 21 deletions(-) + +diff --git a/pcs/lib/sbd.py b/pcs/lib/sbd.py +index caf86a18..0e7f5b92 100644 +--- a/pcs/lib/sbd.py ++++ b/pcs/lib/sbd.py +@@ -302,10 +302,10 @@ def test_watchdog(cmd_runner, watchdog=None): + cmd = [settings.sbd_binary, "test-watchdog"] + if watchdog: + cmd.extend(["-w", watchdog]) +- dummy_std_out, std_err, ret_val = cmd_runner.run(cmd) ++ std_out, dummy_std_err, ret_val = cmd_runner.run(cmd) + if ret_val: +- if "Multiple watchdog devices discovered" in std_err: ++ if "Multiple watchdog devices discovered" in std_out: + raise LibraryError(reports.sbd_watchdog_test_multiple_devices()) +- raise LibraryError(reports.sbd_watchdog_test_error(std_err)) ++ raise LibraryError(reports.sbd_watchdog_test_error(std_out)) + else: + raise LibraryError(reports.sbd_watchdog_test_failed()) +diff --git a/pcs/stonith.py b/pcs/stonith.py +index cc805da8..707321ca 100644 +--- a/pcs/stonith.py ++++ b/pcs/stonith.py +@@ -503,25 +503,13 @@ def sbd_watchdog_list(lib, argv, modifiers): + raise CmdLineInputError() + + available_watchdogs = lib.sbd.get_local_available_watchdogs() +- supported_watchdog_list = [ +- wd for wd, wd_info in available_watchdogs.items() +- if wd_info["caution"] is None +- ] +- unsupported_watchdog_list = [ +- wd for wd in available_watchdogs +- if wd not in supported_watchdog_list +- ] +- +- if supported_watchdog_list: +- print("Supported watchdog(s):") +- for watchdog in supported_watchdog_list: +- print(" {}".format(watchdog)) + +- if unsupported_watchdog_list: +- print("Unsupported watchdog(s):") +- for watchdog in unsupported_watchdog_list: ++ if available_watchdogs: ++ print("Available watchdog(s):") ++ for watchdog in sorted(available_watchdogs.keys()): + print(" {}".format(watchdog)) +- ++ else: ++ print("No available watchdog") + + def sbd_watchdog_list_json(lib, argv, modifiers): + if argv: +diff --git a/pcsd/remote.rb b/pcsd/remote.rb +index 27af41b2..a74f28f5 100644 +--- a/pcsd/remote.rb ++++ b/pcsd/remote.rb +@@ -2408,7 +2408,10 @@ def check_sbd(param, request, auth_user) + :path => watchdog, + :exist => exists, + :is_supported => ( +- exists and available_watchdogs[watchdog]['caution'] == nil ++ # this method is not reliable so all watchdog devices listed by SBD ++ # will be listed as supported for now ++ # exists and available_watchdogs[watchdog]['caution'] == nil ++ exists + ), + } + rescue JSON::ParserError +-- +2.13.6 + diff --git a/SOURCES/bz1488044-01-fix-pcs-cluster-cib-push-for-old-feature-set.patch b/SOURCES/bz1488044-01-fix-pcs-cluster-cib-push-for-old-feature-set.patch new file mode 100644 index 0000000..f4ae99e --- /dev/null +++ b/SOURCES/bz1488044-01-fix-pcs-cluster-cib-push-for-old-feature-set.patch @@ -0,0 +1,229 @@ +From e8d95b4ba03e62658ece669d6389b71b8553df1f Mon Sep 17 00:00:00 2001 +From: Ivan Devat +Date: Wed, 8 Aug 2018 13:48:24 +0200 +Subject: [PATCH] fix pcs cluster cib-push for old feature set + +--- + pcs/cluster.py | 56 +++++++++++++++++++++++++++++++++++++----- + pcs/lib/cib/test/test_tools.py | 29 ++++++++++++++++++++++ + pcs/lib/cib/tools.py | 6 ++--- + pcs/lib/env.py | 10 ++++++-- + 4 files changed, 90 insertions(+), 11 deletions(-) + +diff --git a/pcs/cluster.py b/pcs/cluster.py +index b4d49d27..e8c94ab8 100644 +--- a/pcs/cluster.py ++++ b/pcs/cluster.py +@@ -35,6 +35,7 @@ from pcs import ( + ) + from pcs.utils import parallel_for_nodes + from pcs.common import report_codes ++from pcs.common.tools import Version + from pcs.cli.common.errors import ( + CmdLineInputError, + ERR_NODE_LIST_AND_ALL_MUTUALLY_EXCLUSIVE, +@@ -46,6 +47,7 @@ from pcs.lib import ( + reports as lib_reports, + ) + from pcs.lib.booth import sync as booth_sync ++from pcs.lib.cib.tools import VERSION_FORMAT + from pcs.lib.commands.remote_node import _share_authkey, _destroy_pcmk_remote_env + from pcs.lib.commands.quorum import _add_device_model_net + from pcs.lib.communication.corosync import CheckCorosyncOffline +@@ -74,6 +76,7 @@ from pcs.lib.external import ( + NodeCommunicationException, + node_communicator_exception_to_report_item, + ) ++from pcs.lib.env import MIN_FEATURE_SET_VERSION_FOR_DIFF + from pcs.lib.env_tools import get_nodes + from pcs.lib.node import NodeAddresses + from pcs.lib import node_communication_format +@@ -1566,21 +1569,62 @@ def cluster_push(argv): + + if diff_against: + try: +- xml.dom.minidom.parse(diff_against) ++ original_cib = xml.dom.minidom.parse(diff_against) + except (EnvironmentError, xml.parsers.expat.ExpatError) as e: + utils.err("unable to parse original cib: %s" % e) ++ ++ def unable_to_diff(reason): ++ return error( ++ "unable to diff against original cib '{0}': {1}" ++ .format(diff_against, reason) ++ ) ++ ++ cib_element_list = original_cib.getElementsByTagName("cib") ++ ++ if len(cib_element_list) != 1: ++ raise unable_to_diff("there is not exactly one 'cib' element") ++ ++ crm_feature_set = cib_element_list[0].getAttribute("crm_feature_set") ++ if not crm_feature_set: ++ raise unable_to_diff( ++ "the 'cib' element is missing 'crm_feature_set' value" ++ ) ++ ++ match = re.match(VERSION_FORMAT, crm_feature_set) ++ if not match: ++ raise unable_to_diff( ++ "the attribute 'crm_feature_set' of the element 'cib' has an" ++ " invalid value: '{0}'".format(crm_feature_set) ++ ) ++ crm_feature_set_version = Version( ++ int(match.group("major")), ++ int(match.group("minor")), ++ int(match.group("rev")) if match.group("rev") else None ++ ) ++ ++ if crm_feature_set_version < MIN_FEATURE_SET_VERSION_FOR_DIFF: ++ raise unable_to_diff( ++ ( ++ "the 'crm_feature_set' version is '{0}'" ++ " but at least version '{1}' is required" ++ ).format( ++ crm_feature_set_version, ++ MIN_FEATURE_SET_VERSION_FOR_DIFF, ++ ) ++ ) ++ + runner = utils.cmd_runner() + command = [ + "crm_diff", "--original", diff_against, "--new", filename, + "--no-version" + ] +- patch, error, dummy_retval = runner.run(command) ++ patch, stderr, dummy_retval = runner.run(command) + # dummy_retval == 1 means one of two things: + # a) an error has occured + # b) --original and --new differ + # therefore it's of no use to see if an error occurred +- if error.strip(): +- utils.err("unable to diff the CIBs:\n" + error) ++ if stderr.strip(): ++ utils.err("unable to diff the CIBs:\n" + stderr) + if not patch.strip(): + print( + "The new CIB is the same as the original CIB, nothing to push." +@@ -1588,9 +1632,9 @@ def cluster_push(argv): + sys.exit(0) + + command = ["cibadmin", "--patch", "--xml-pipe"] +- output, error, retval = runner.run(command, patch) ++ output, stderr, retval = runner.run(command, patch) + if retval != 0: +- utils.err("unable to push cib\n" + error + output) ++ utils.err("unable to push cib\n" + stderr + output) + + else: + command = ["cibadmin", "--replace", "--xml-file", filename] +diff --git a/pcs/lib/cib/test/test_tools.py b/pcs/lib/cib/test/test_tools.py +index fab39ce7..2bdc7695 100644 +--- a/pcs/lib/cib/test/test_tools.py ++++ b/pcs/lib/cib/test/test_tools.py +@@ -436,6 +436,21 @@ class GetPacemakerVersionByWhichCibWasValidatedTest(TestCase): + ) + ) + ++ def test_invalid_version_at_end(self): ++ assert_raise_library_error( ++ lambda: lib.get_pacemaker_version_by_which_cib_was_validated( ++ etree.XML('') ++ ), ++ ( ++ severities.ERROR, ++ report_codes.CIB_LOAD_ERROR_BAD_FORMAT, ++ { ++ "reason": "the attribute 'validate-with' of the element" ++ " 'cib' has an invalid value: 'pacemaker-1.2.3x'" ++ } ++ ) ++ ) ++ + def test_no_revision(self): + self.assertEqual( + Version(1, 2), +@@ -507,6 +522,20 @@ class getCibCrmFeatureSet(TestCase): + ) + ) + ++ def test_invalid_version_at_end(self): ++ assert_raise_library_error( ++ lambda: lib.get_cib_crm_feature_set( ++ etree.XML('') ++ ), ++ fixture.error( ++ report_codes.CIB_LOAD_ERROR_BAD_FORMAT, ++ reason=( ++ "the attribute 'crm_feature_set' of the element 'cib' has " ++ "an invalid value: '3.0.9x'" ++ ) ++ ) ++ ) ++ + + find_group = partial(lib.find_element_by_tag_and_id, "group") + class FindTagWithId(TestCase): +diff --git a/pcs/lib/cib/tools.py b/pcs/lib/cib/tools.py +index 2cff96f3..ab2a9df5 100644 +--- a/pcs/lib/cib/tools.py ++++ b/pcs/lib/cib/tools.py +@@ -16,7 +16,7 @@ from pcs.lib.pacemaker.values import ( + ) + from pcs.lib.xml_tools import get_root, get_sub_element + +-_VERSION_FORMAT = r"(?P\d+)\.(?P\d+)(\.(?P\d+))?" ++VERSION_FORMAT = r"(?P\d+)\.(?P\d+)(\.(?P\d+))?$" + + class IdProvider(object): + """ +@@ -289,7 +289,7 @@ def get_pacemaker_version_by_which_cib_was_validated(cib): + return _get_cib_version( + cib, + "validate-with", +- re.compile(r"pacemaker-{0}".format(_VERSION_FORMAT)) ++ re.compile(r"pacemaker-{0}".format(VERSION_FORMAT)) + ) + + def get_cib_crm_feature_set(cib, none_if_missing=False): +@@ -303,6 +303,6 @@ def get_cib_crm_feature_set(cib, none_if_missing=False): + return _get_cib_version( + cib, + "crm_feature_set", +- re.compile(_VERSION_FORMAT), ++ re.compile(r"^{0}".format(VERSION_FORMAT)), + none_if_missing=none_if_missing + ) +diff --git a/pcs/lib/env.py b/pcs/lib/env.py +index 86f67b64..3b2c06b6 100644 +--- a/pcs/lib/env.py ++++ b/pcs/lib/env.py +@@ -57,6 +57,8 @@ from pcs.lib.pacemaker.values import get_valid_timeout_seconds + from pcs.lib.tools import write_tmpfile + from pcs.lib.xml_tools import etree_to_str + ++MIN_FEATURE_SET_VERSION_FOR_DIFF = Version(3, 0, 9) ++ + class LibraryEnvironment(object): + # pylint: disable=too-many-instance-attributes + +@@ -211,10 +213,14 @@ class LibraryEnvironment(object): + # only check the version if a CIB has been loaded, otherwise the push + # fails anyway. By my testing it seems that only the source CIB's + # version matters. +- if self.__loaded_cib_diff_source_feature_set < Version(3, 0, 9): ++ if( ++ self.__loaded_cib_diff_source_feature_set ++ < ++ MIN_FEATURE_SET_VERSION_FOR_DIFF ++ ): + self.report_processor.process( + reports.cib_push_forced_full_due_to_crm_feature_set( +- Version(3, 0, 9), ++ MIN_FEATURE_SET_VERSION_FOR_DIFF, + self.__loaded_cib_diff_source_feature_set + ) + ) +-- +2.13.6 + diff --git a/SOURCES/bz1522813-01-fix-a-crash-when-wait-is-used-in-stonith-create.patch b/SOURCES/bz1522813-01-fix-a-crash-when-wait-is-used-in-stonith-create.patch deleted file mode 100644 index 43e4784..0000000 --- a/SOURCES/bz1522813-01-fix-a-crash-when-wait-is-used-in-stonith-create.patch +++ /dev/null @@ -1,524 +0,0 @@ -From 663143e3abbf2798a3c780c691242511b64046a2 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Wed, 6 Dec 2017 17:38:15 +0100 -Subject: [PATCH] fix a crash when --wait is used in stonith create - ---- - pcs/lib/commands/stonith.py | 19 ++- - pcs/lib/commands/test/test_stonith.py | 188 ++++++++++++++++++++++ - pcs/lib/resource_agent.py | 4 + - pcs/test/resources/stonith_agent_fence_simple.xml | 33 ++++ - pcs/test/resources/stonithd_metadata.xml | 156 ++++++++++++++++++ - pcs/test/tools/command_env/config_runner_pcmk.py | 36 +++++ - 6 files changed, 430 insertions(+), 6 deletions(-) - create mode 100644 pcs/lib/commands/test/test_stonith.py - create mode 100644 pcs/test/resources/stonith_agent_fence_simple.xml - create mode 100644 pcs/test/resources/stonithd_metadata.xml - -diff --git a/pcs/lib/commands/stonith.py b/pcs/lib/commands/stonith.py -index bb9fb98..584e1b2 100644 ---- a/pcs/lib/commands/stonith.py -+++ b/pcs/lib/commands/stonith.py -@@ -4,11 +4,14 @@ from __future__ import ( - print_function, - ) - --from pcs.lib.resource_agent import find_valid_stonith_agent_by_name as get_agent - from pcs.lib.cib import resource - from pcs.lib.cib.resource.common import are_meta_disabled -+from pcs.lib.commands.resource import ( -+ _ensure_disabled_after_wait, -+ resource_environment -+) - from pcs.lib.pacemaker.values import validate_id --from pcs.lib.commands.resource import resource_environment -+from pcs.lib.resource_agent import find_valid_stonith_agent_by_name as get_agent - - def create( - env, stonith_id, stonith_agent_name, -@@ -55,8 +58,10 @@ def create( - with resource_environment( - env, - wait, -- stonith_id, -- ensure_disabled or are_meta_disabled(meta_attributes), -+ [stonith_id], -+ _ensure_disabled_after_wait( -+ ensure_disabled or are_meta_disabled(meta_attributes), -+ ) - ) as resources_section: - stonith_element = resource.primitive.create( - env.report_processor, -@@ -125,8 +130,10 @@ def create_in_group( - with resource_environment( - env, - wait, -- stonith_id, -- ensure_disabled or are_meta_disabled(meta_attributes), -+ [stonith_id], -+ _ensure_disabled_after_wait( -+ ensure_disabled or are_meta_disabled(meta_attributes), -+ ) - ) as resources_section: - stonith_element = resource.primitive.create( - env.report_processor, resources_section, -diff --git a/pcs/lib/commands/test/test_stonith.py b/pcs/lib/commands/test/test_stonith.py -new file mode 100644 -index 0000000..912742f ---- /dev/null -+++ b/pcs/lib/commands/test/test_stonith.py -@@ -0,0 +1,188 @@ -+from __future__ import ( -+ absolute_import, -+ division, -+ print_function, -+) -+ -+from pcs.common import report_codes -+from pcs.lib.commands import stonith -+from pcs.lib.resource_agent import StonithAgent -+from pcs.test.tools import fixture -+from pcs.test.tools.command_env import get_env_tools -+from pcs.test.tools.pcs_unittest import TestCase -+ -+ -+class Create(TestCase): -+ def setUp(self): -+ self.env_assist, self.config = get_env_tools(test_case=self) -+ self.agent_name = "test_simple" -+ self.instance_name = "stonith-test" -+ self.timeout = 10 -+ self.expected_cib = """ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ """ -+ self.expected_status = """ -+ -+ -+ -+ -+ -+ """.format(id=self.instance_name, agent=self.agent_name) -+ (self.config -+ .runner.pcmk.load_agent( -+ agent_name="stonith:{0}".format(self.agent_name), -+ agent_filename="stonith_agent_fence_simple.xml" -+ ) -+ .runner.cib.load() -+ .runner.pcmk.load_stonithd_metadata() -+ ) -+ -+ def tearDown(self): -+ StonithAgent.clear_stonithd_metadata_cache() -+ -+ def test_minimal_success(self): -+ self.config.env.push_cib(resources=self.expected_cib) -+ stonith.create( -+ self.env_assist.get_env(), -+ self.instance_name, -+ self.agent_name, -+ operations=[], -+ meta_attributes={}, -+ instance_attributes={"must-set": "value"} -+ ) -+ -+ def test_minimal_wait_ok_run_ok(self): -+ (self.config -+ .runner.pcmk.can_wait(before="runner.cib.load") -+ .env.push_cib( -+ resources=self.expected_cib, -+ wait=self.timeout -+ ) -+ .runner.pcmk.load_state(resources=self.expected_status) -+ ) -+ stonith.create( -+ self.env_assist.get_env(), -+ self.instance_name, -+ self.agent_name, -+ operations=[], -+ meta_attributes={}, -+ instance_attributes={"must-set": "value"}, -+ wait=self.timeout -+ ) -+ self.env_assist.assert_reports([ -+ fixture.info( -+ report_codes.RESOURCE_RUNNING_ON_NODES, -+ roles_with_nodes={"Started": ["node1"]}, -+ resource_id=self.instance_name, -+ ), -+ ]) -+ -+ -+class CreateInGroup(TestCase): -+ def setUp(self): -+ self.env_assist, self.config = get_env_tools(test_case=self) -+ self.agent_name = "test_simple" -+ self.instance_name = "stonith-test" -+ self.timeout = 10 -+ self.expected_cib = """ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ """ -+ self.expected_status = """ -+ -+ -+ -+ -+ -+ """.format(id=self.instance_name, agent=self.agent_name) -+ (self.config -+ .runner.pcmk.load_agent( -+ agent_name="stonith:{0}".format(self.agent_name), -+ agent_filename="stonith_agent_fence_simple.xml" -+ ) -+ .runner.cib.load() -+ .runner.pcmk.load_stonithd_metadata() -+ ) -+ -+ def tearDown(self): -+ StonithAgent.clear_stonithd_metadata_cache() -+ -+ def test_minimal_success(self): -+ self.config.env.push_cib(resources=self.expected_cib) -+ stonith.create_in_group( -+ self.env_assist.get_env(), -+ self.instance_name, -+ self.agent_name, -+ "my-group", -+ operations=[], -+ meta_attributes={}, -+ instance_attributes={"must-set": "value"} -+ ) -+ -+ def test_minimal_wait_ok_run_ok(self): -+ (self.config -+ .runner.pcmk.can_wait(before="runner.cib.load") -+ .env.push_cib( -+ resources=self.expected_cib, -+ wait=self.timeout -+ ) -+ .runner.pcmk.load_state(resources=self.expected_status) -+ ) -+ stonith.create_in_group( -+ self.env_assist.get_env(), -+ self.instance_name, -+ self.agent_name, -+ "my-group", -+ operations=[], -+ meta_attributes={}, -+ instance_attributes={"must-set": "value"}, -+ wait=self.timeout -+ ) -+ self.env_assist.assert_reports([ -+ fixture.info( -+ report_codes.RESOURCE_RUNNING_ON_NODES, -+ roles_with_nodes={"Started": ["node1"]}, -+ resource_id=self.instance_name, -+ ), -+ ]) -diff --git a/pcs/lib/resource_agent.py b/pcs/lib/resource_agent.py -index 4639477..2f2686d 100644 ---- a/pcs/lib/resource_agent.py -+++ b/pcs/lib/resource_agent.py -@@ -836,6 +836,10 @@ class StonithAgent(CrmAgent): - """ - _stonithd_metadata = None - -+ @classmethod -+ def clear_stonithd_metadata_cache(cls): -+ cls._stonithd_metadata = None -+ - def _prepare_name_parts(self, name): - # pacemaker doesn't support stonith (nor resource) agents with : in type - if ":" in name: -diff --git a/pcs/test/resources/stonith_agent_fence_simple.xml b/pcs/test/resources/stonith_agent_fence_simple.xml -new file mode 100644 -index 0000000..bb86af2 ---- /dev/null -+++ b/pcs/test/resources/stonith_agent_fence_simple.xml -@@ -0,0 +1,33 @@ -+ -+ -+ -+ This is a testing fence agent. Its purpose is to provide a mock of a fence -+ agent which is always available no matter what is the configuration of a -+ system pcs test suite runs on. -+ -+ https://github.com/ClusterLabs/pcs -+ -+ -+ -+ An example of a required attribute -+ -+ -+ -+ An example of an optional attribute -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pcs/test/resources/stonithd_metadata.xml b/pcs/test/resources/stonithd_metadata.xml -new file mode 100644 -index 0000000..fc638a2 ---- /dev/null -+++ b/pcs/test/resources/stonithd_metadata.xml -@@ -0,0 +1,156 @@ -+ -+ -+ 1.0 -+ This is a fake resource that details the instance attributes handled by stonithd. -+ Options available for all stonith resources -+ -+ -+ The priority of the stonith resource. Devices are tried in order of highest priority to lowest. -+ -+ -+ -+ Advanced use only: An alternate parameter to supply instead of 'port' -+ Some devices do not support the standard 'port' parameter or may provide additional ones. -+Use this to specify an alternate, device-specific, parameter that should indicate the machine to be fenced. -+A value of 'none' can be used to tell the cluster not to supply any additional parameters. -+ -+ -+ -+ -+ A mapping of host names to ports numbers for devices that do not support host names. -+ Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and ports 2 and 3 for node2 -+ -+ -+ -+ A list of machines controlled by this device (Optional unless pcmk_host_check=static-list). -+ -+ -+ -+ How to determine which machines are controlled by the device. -+ Allowed values: dynamic-list (query the device), static-list (check the pcmk_host_list attribute), none (assume every device can fence every machine) -+ -+ -+ -+ Enable a random delay for stonith actions and specify the maximum of random delay. -+ This prevents double fencing when using slow devices such as sbd. -+Use this to enable a random delay for stonith actions. -+The overall delay is derived from this random delay value adding a static delay so that the sum is kept below the maximum delay. -+ -+ -+ -+ Enable a base delay for stonith actions and specify base delay value. -+ This prevents double fencing when different delays are configured on the nodes. -+Use this to enable a static delay for stonith actions. -+The overall delay is derived from a random delay value adding this static delay so that the sum is kept below the maximum delay. -+ -+ -+ -+ The maximum number of actions can be performed in parallel on this device -+ Pengine property concurrent-fencing=true needs to be configured first. -+Then use this to specify the maximum number of actions can be performed in parallel on this device. -1 is unlimited. -+ -+ -+ -+ Advanced use only: An alternate command to run instead of 'reboot' -+ Some devices do not support the standard commands or may provide additional ones. -+Use this to specify an alternate, device-specific, command that implements the 'reboot' action. -+ -+ -+ -+ Advanced use only: Specify an alternate timeout to use for reboot actions instead of stonith-timeout -+ Some devices need much more/less time to complete than normal. -+Use this to specify an alternate, device-specific, timeout for 'reboot' actions. -+ -+ -+ -+ Advanced use only: The maximum number of times to retry the 'reboot' command within the timeout period -+ Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'reboot' actions before giving up. -+ -+ -+ -+ Advanced use only: An alternate command to run instead of 'off' -+ Some devices do not support the standard commands or may provide additional ones. -+Use this to specify an alternate, device-specific, command that implements the 'off' action. -+ -+ -+ -+ Advanced use only: Specify an alternate timeout to use for off actions instead of stonith-timeout -+ Some devices need much more/less time to complete than normal. -+Use this to specify an alternate, device-specific, timeout for 'off' actions. -+ -+ -+ -+ Advanced use only: The maximum number of times to retry the 'off' command within the timeout period -+ Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'off' actions before giving up. -+ -+ -+ -+ Advanced use only: An alternate command to run instead of 'on' -+ Some devices do not support the standard commands or may provide additional ones. -+Use this to specify an alternate, device-specific, command that implements the 'on' action. -+ -+ -+ -+ Advanced use only: Specify an alternate timeout to use for on actions instead of stonith-timeout -+ Some devices need much more/less time to complete than normal. -+Use this to specify an alternate, device-specific, timeout for 'on' actions. -+ -+ -+ -+ Advanced use only: The maximum number of times to retry the 'on' command within the timeout period -+ Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'on' actions before giving up. -+ -+ -+ -+ Advanced use only: An alternate command to run instead of 'list' -+ Some devices do not support the standard commands or may provide additional ones. -+Use this to specify an alternate, device-specific, command that implements the 'list' action. -+ -+ -+ -+ Advanced use only: Specify an alternate timeout to use for list actions instead of stonith-timeout -+ Some devices need much more/less time to complete than normal. -+Use this to specify an alternate, device-specific, timeout for 'list' actions. -+ -+ -+ -+ Advanced use only: The maximum number of times to retry the 'list' command within the timeout period -+ Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'list' actions before giving up. -+ -+ -+ -+ Advanced use only: An alternate command to run instead of 'monitor' -+ Some devices do not support the standard commands or may provide additional ones. -+Use this to specify an alternate, device-specific, command that implements the 'monitor' action. -+ -+ -+ -+ Advanced use only: Specify an alternate timeout to use for monitor actions instead of stonith-timeout -+ Some devices need much more/less time to complete than normal. -+Use this to specify an alternate, device-specific, timeout for 'monitor' actions. -+ -+ -+ -+ Advanced use only: The maximum number of times to retry the 'monitor' command within the timeout period -+ Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'monitor' actions before giving up. -+ -+ -+ -+ Advanced use only: An alternate command to run instead of 'status' -+ Some devices do not support the standard commands or may provide additional ones. -+Use this to specify an alternate, device-specific, command that implements the 'status' action. -+ -+ -+ -+ Advanced use only: Specify an alternate timeout to use for status actions instead of stonith-timeout -+ Some devices need much more/less time to complete than normal. -+Use this to specify an alternate, device-specific, timeout for 'status' actions. -+ -+ -+ -+ Advanced use only: The maximum number of times to retry the 'status' command within the timeout period -+ Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'status' actions before giving up. -+ -+ -+ -+ -diff --git a/pcs/test/tools/command_env/config_runner_pcmk.py b/pcs/test/tools/command_env/config_runner_pcmk.py -index 6499ef8..059f3eb 100644 ---- a/pcs/test/tools/command_env/config_runner_pcmk.py -+++ b/pcs/test/tools/command_env/config_runner_pcmk.py -@@ -70,6 +70,42 @@ class PcmkShortcuts(object): - instead=instead, - ) - -+ def load_stonithd_metadata( -+ self, -+ name="runner.pcmk.load_stonithd_metadata", -+ stdout=None, -+ stderr="", -+ returncode=0, -+ instead=None, -+ before=None, -+ ): -+ """ -+ Create a call for loading stonithd metadata - additional fence options -+ -+ string name -- the key of this call -+ string stdout -- stonithd stdout, default metadata if None -+ string stderr -- stonithd stderr -+ int returncode -- stonithd returncode -+ string instead -- the key of a call instead of which this new call is to -+ be placed -+ string before -- the key of a call before which this new call is to be -+ placed -+ """ -+ self.__calls.place( -+ name, -+ RunnerCall( -+ "/usr/libexec/pacemaker/stonithd metadata", -+ stdout=( -+ stdout if stdout is not None -+ else open(rc("stonithd_metadata.xml")).read() -+ ), -+ stderr=stderr, -+ returncode=returncode -+ ), -+ before=before, -+ instead=instead, -+ ) -+ - def resource_cleanup( - self, - name="runner.pcmk.cleanup", --- -1.8.3.1 - diff --git a/SOURCES/bz1523378-01-warn-when-a-stonith-device-has-method-cycle-set.patch b/SOURCES/bz1523378-01-warn-when-a-stonith-device-has-method-cycle-set.patch deleted file mode 100644 index 0da5ae3..0000000 --- a/SOURCES/bz1523378-01-warn-when-a-stonith-device-has-method-cycle-set.patch +++ /dev/null @@ -1,261 +0,0 @@ -From b3b7bf416724f424a280c63f94121fb47e7397e6 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Mon, 11 Dec 2017 08:54:26 +0100 -Subject: [PATCH] warn when a stonith device has method=cycle set - ---- - pcs/status.py | 21 ++++++++++++++-- - pcs/test/test_status.py | 47 ++++++++++++++++++++++++----------- - pcsd/cluster_entity.rb | 22 +++++++++++++++++ - pcsd/test/cib1.xml | 2 ++ - pcsd/test/test_cluster_entity.rb | 53 ++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 129 insertions(+), 16 deletions(-) - -diff --git a/pcs/status.py b/pcs/status.py -index ec10d61..8a517be 100644 ---- a/pcs/status.py -+++ b/pcs/status.py -@@ -125,6 +125,7 @@ def status_stonith_check(): - stonith_enabled = True - stonith_devices = [] - stonith_devices_id_action = [] -+ stonith_devices_id_method_cycle = [] - sbd_running = False - - cib = utils.get_cib_dom() -@@ -155,6 +156,14 @@ def status_stonith_check(): - stonith_devices_id_action.append( - resource.getAttribute("id") - ) -+ if ( -+ nvpair.getAttribute("name") == "method" -+ and -+ nvpair.getAttribute("value") == "cycle" -+ ): -+ stonith_devices_id_method_cycle.append( -+ resource.getAttribute("id") -+ ) - - if not utils.usefile: - # check if SBD daemon is running -@@ -171,14 +180,22 @@ def status_stonith_check(): - - if stonith_devices_id_action: - print( -- "WARNING: following stonith devices have the 'action' attribute" -- " set, it is recommended to set {0} instead: {1}".format( -+ "WARNING: following stonith devices have the 'action' option set, " -+ "it is recommended to set {0} instead: {1}".format( - ", ".join( - ["'{0}'".format(x) for x in _STONITH_ACTION_REPLACED_BY] - ), - ", ".join(sorted(stonith_devices_id_action)) - ) - ) -+ if stonith_devices_id_method_cycle: -+ print( -+ "WARNING: following stonith devices have the 'method' option set " -+ "to 'cycle' which is potentially dangerous, please consider using " -+ "'onoff': {0}".format( -+ ", ".join(sorted(stonith_devices_id_method_cycle)) -+ ) -+ ) - - # Parse crm_mon for status - def nodes_status(argv): -diff --git a/pcs/test/test_status.py b/pcs/test/test_status.py -index b412b91..1a4fb70 100644 ---- a/pcs/test/test_status.py -+++ b/pcs/test/test_status.py -@@ -21,45 +21,64 @@ class StonithWarningTest(TestCase, AssertPcsMixin): - shutil.copy(self.empty_cib, self.temp_cib) - self.pcs_runner = PcsRunner(self.temp_cib) - -- def fixture_stonith(self, action=False): -+ def fixture_stonith_action(self): - self.assert_pcs_success( -- "stonith create S fence_apc ipaddr=i login=l {0} --force".format( -- "action=reboot" if action else "" -- ), -+ "stonith create Sa fence_apc ipaddr=i login=l action=reboot --force", - "Warning: stonith option 'action' is deprecated and should not be" - " used, use pcmk_off_action, pcmk_reboot_action instead\n" -- if action -- else "" -+ ) -+ -+ def fixture_stonith_cycle(self): -+ self.assert_pcs_success( -+ "stonith create Sc fence_ipmilan method=cycle" - ) - - def fixture_resource(self): - self.assert_pcs_success( -- "resource create dummy ocf:pacemaker:Dummy action=reboot --force", -- "Warning: invalid resource option 'action', allowed options are: " -- "envfile, fail_start_on, fake, op_sleep, passwd, state," -- " trace_file, trace_ra\n" -+ "resource create dummy ocf:pacemaker:Dummy action=reboot " -+ "method=cycle --force" -+ , -+ "Warning: invalid resource options: 'action', 'method', allowed " -+ "options are: envfile, fail_start_on, fake, op_sleep, passwd, " -+ "state, trace_file, trace_ra\n" - ) - - def test_warning_stonith_action(self): -- self.fixture_stonith(action=True) -+ self.fixture_stonith_action() -+ self.fixture_resource() - self.assert_pcs_success( - "status", - stdout_start=dedent("""\ - Cluster name: test99 -- WARNING: following stonith devices have the 'action' attribute set, it is recommended to set 'pcmk_off_action', 'pcmk_reboot_action' instead: S -+ WARNING: following stonith devices have the 'action' option set, it is recommended to set 'pcmk_off_action', 'pcmk_reboot_action' instead: Sa - Stack: unknown - Current DC: NONE - """) - ) - -- def test_action_ignored_for_non_stonith_resources(self): -- self.fixture_stonith(action=False) -+ def test_warning_stonith_method_cycle(self): -+ self.fixture_stonith_cycle() - self.fixture_resource() -+ self.assert_pcs_success( -+ "status", -+ stdout_start=dedent("""\ -+ Cluster name: test99 -+ WARNING: following stonith devices have the 'method' option set to 'cycle' which is potentially dangerous, please consider using 'onoff': Sc -+ Stack: unknown -+ Current DC: NONE -+ """) -+ ) - -+ def test_stonith_warnings(self): -+ self.fixture_stonith_action() -+ self.fixture_stonith_cycle() -+ self.fixture_resource() - self.assert_pcs_success( - "status", - stdout_start=dedent("""\ - Cluster name: test99 -+ WARNING: following stonith devices have the 'action' option set, it is recommended to set 'pcmk_off_action', 'pcmk_reboot_action' instead: Sa -+ WARNING: following stonith devices have the 'method' option set to 'cycle' which is potentially dangerous, please consider using 'onoff': Sc - Stack: unknown - Current DC: NONE - """) -diff --git a/pcsd/cluster_entity.rb b/pcsd/cluster_entity.rb -index 21092c5..3675719 100644 ---- a/pcsd/cluster_entity.rb -+++ b/pcsd/cluster_entity.rb -@@ -516,6 +516,28 @@ module ClusterEntity - @utilization << ClusterEntity::NvPair.from_dom(e) - } - @stonith = @_class == 'stonith' -+ if @stonith -+ @instance_attr.each{ |attr| -+ if attr.name == 'action' -+ @warning_list << { -+ :message => ( -+ 'This fence-device has the "action" option set, it is ' + -+ 'recommended to set "pcmk_off_action", "pcmk_reboot_action" ' + -+ 'instead' -+ ) -+ } -+ end -+ if attr.name == 'method' and attr.value == 'cycle' -+ @warning_list << { -+ :message => ( -+ 'This fence-device has the "method" option set to "cycle" ' + -+ 'which is potentially dangerous, please consider using ' + -+ '"onoff"' -+ ) -+ } -+ end -+ } -+ end - if @id and rsc_status - @crm_status = rsc_status[@id] || [] - end -diff --git a/pcsd/test/cib1.xml b/pcsd/test/cib1.xml -index f603f24..03749ab 100644 ---- a/pcsd/test/cib1.xml -+++ b/pcsd/test/cib1.xml -@@ -28,6 +28,8 @@ - - - -+ -+ - - - -diff --git a/pcsd/test/test_cluster_entity.rb b/pcsd/test/test_cluster_entity.rb -index 2b67e19..60719ef 100644 ---- a/pcsd/test/test_cluster_entity.rb -+++ b/pcsd/test/test_cluster_entity.rb -@@ -719,6 +719,59 @@ class TestPrimitive < Test::Unit::TestCase - assert(obj.operations.empty?) - end - -+ def test_init_stonith_with_warnings -+ obj = ClusterEntity::Primitive.new( -+ @cib.elements["//primitive[@id='node2-stonith']"] -+ ) -+ assert_nil(obj.parent) -+ assert_nil(obj.get_master) -+ assert_nil(obj.get_clone) -+ assert_nil(obj.get_group) -+ assert(obj.meta_attr.empty?) -+ assert_equal('node2-stonith', obj.id) -+ assert(obj.error_list.empty?) -+ assert_equal( -+ obj.warning_list, -+ [ -+ { -+ :message => ( -+ 'This fence-device has the "action" option set, it is ' + -+ 'recommended to set "pcmk_off_action", "pcmk_reboot_action" instead' -+ ) -+ }, -+ { -+ :message => ( -+ 'This fence-device has the "method" option set to "cycle" which ' + -+ 'is potentially dangerous, please consider using "onoff"' -+ ) -+ } -+ ] -+ ) -+ assert_equal('stonith:fence_xvm', obj.agentname) -+ assert_equal('stonith', obj._class) -+ assert_nil(obj.provider) -+ assert_equal('fence_xvm', obj.type) -+ assert(obj.stonith) -+ instance_attr = ClusterEntity::NvSet.new << ClusterEntity::NvPair.new( -+ 'node2-stonith-instance_attributes-domain', -+ 'domain', -+ 'node2' -+ ) -+ instance_attr << ClusterEntity::NvPair.new( -+ 'node2-stonith-instance_attributes-action', -+ 'action', -+ 'monitor' -+ ) -+ instance_attr << ClusterEntity::NvPair.new( -+ 'node2-stonith-instance_attributes-method', -+ 'method', -+ 'cycle' -+ ) -+ assert_equal_NvSet(instance_attr, obj.instance_attr) -+ assert(obj.crm_status.empty?) -+ assert(obj.operations.empty?) -+ end -+ - def test_init_stonith_with_crm - obj = ClusterEntity::Primitive.new( - @cib.elements["//primitive[@id='node1-stonith']"], --- -1.8.3.1 - diff --git a/SOURCES/bz1527530-01-fix-a-crash-in-pcs-booth-sync.patch b/SOURCES/bz1527530-01-fix-a-crash-in-pcs-booth-sync.patch deleted file mode 100644 index 0bd88e7..0000000 --- a/SOURCES/bz1527530-01-fix-a-crash-in-pcs-booth-sync.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 772b48493eb19f2d9e25579740edd6216c9f8ed0 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Thu, 4 Jan 2018 13:22:03 +0100 -Subject: [PATCH] fix a crash in 'pcs booth sync' - ---- - pcs/lib/communication/booth.py | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/pcs/lib/communication/booth.py b/pcs/lib/communication/booth.py -index 240738a..a3aa918 100644 ---- a/pcs/lib/communication/booth.py -+++ b/pcs/lib/communication/booth.py -@@ -10,6 +10,7 @@ import os - - from pcs.common.node_communicator import RequestData - from pcs.lib import reports -+from pcs.lib.booth import reports as reports_booth - from pcs.lib.communication.tools import ( - AllAtOnceStrategyMixin, - AllSameDataMixin, -@@ -51,12 +52,12 @@ class BoothSendConfig( - ) - - def _get_success_report(self, node_label): -- return reports.booth_config_accepted_by_node( -+ return reports_booth.booth_config_accepted_by_node( - node_label, [self._booth_name] - ) - - def before(self): -- self._report(reports.booth_config_distribution_started()) -+ self._report(reports_booth.booth_config_distribution_started()) - - - class ProcessJsonDataMixin(object): --- -1.8.3.1 - diff --git a/SOURCES/bz1557253-01-get-rid-of-debug-when-calling-local-pcsd.patch b/SOURCES/bz1557253-01-get-rid-of-debug-when-calling-local-pcsd.patch deleted file mode 100644 index 1f0a51f..0000000 --- a/SOURCES/bz1557253-01-get-rid-of-debug-when-calling-local-pcsd.patch +++ /dev/null @@ -1,53 +0,0 @@ -From b14467358acacb5ff492f2df29c2c76abb9df180 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Tue, 20 Mar 2018 15:39:40 +0100 -Subject: [PATCH 1/3] get rid of --debug when calling local pcsd - ---- - pcsd/pcsd.rb | 15 ++++++++++----- - 1 file changed, 10 insertions(+), 5 deletions(-) - -diff --git a/pcsd/pcsd.rb b/pcsd/pcsd.rb -index 8f5ad819..b6a7435c 100644 ---- a/pcsd/pcsd.rb -+++ b/pcsd/pcsd.rb -@@ -239,8 +239,13 @@ post '/run_pcs' do - } - return JSON.pretty_generate(result) - end -- # do not reveal potentialy sensitive information -- command_decoded.delete('--debug') -+ # Do not reveal potentially sensitive information: remove --debug and all its -+ # prefixes since getopt parser in pcs considers them equal to --debug. -+ debug_items = ["--de", "--deb", "--debu", "--debug"] -+ command_sanitized = [] -+ command_decoded.each { |item| -+ command_sanitized << item unless debug_items.include?(item) -+ } - - allowed_commands = { - ['cluster', 'auth', '...'] => { -@@ -341,9 +346,9 @@ post '/run_pcs' do - allowed = false - command_settings = {} - allowed_commands.each { |cmd, cmd_settings| -- if command_decoded == cmd \ -+ if command_sanitized == cmd \ - or \ -- (cmd[-1] == '...' and cmd[0..-2] == command_decoded[0..(cmd.length - 2)]) -+ (cmd[-1] == '...' and cmd[0..-2] == command_sanitized[0..(cmd.length - 2)]) - then - allowed = true - command_settings = cmd_settings -@@ -372,7 +377,7 @@ post '/run_pcs' do - options = {} - options['stdin'] = std_in if std_in - std_out, std_err, retval = run_cmd_options( -- @auth_user, options, PCS, *command_decoded -+ @auth_user, options, PCS, *command_sanitized - ) - result = { - 'status' => 'ok', --- -2.13.6 - diff --git a/SOURCES/bz1557253-02-sanitize-path-when-saving-booth-config-files.patch b/SOURCES/bz1557253-02-sanitize-path-when-saving-booth-config-files.patch deleted file mode 100644 index 429c3be..0000000 --- a/SOURCES/bz1557253-02-sanitize-path-when-saving-booth-config-files.patch +++ /dev/null @@ -1,28 +0,0 @@ -From b2cdeb7a94cd1051a05d9de9a34bfbb54dd1a1df Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Tue, 20 Mar 2018 15:44:59 +0100 -Subject: [PATCH 2/3] sanitize path when saving booth config files - ---- - pcsd/pcsd_file.rb | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/pcsd/pcsd_file.rb b/pcsd/pcsd_file.rb -index de7d3553..4f1604a8 100644 ---- a/pcsd/pcsd_file.rb -+++ b/pcsd/pcsd_file.rb -@@ -104,6 +104,11 @@ module PcsdFile - if @file[:name].empty? - raise PcsdExchangeFormat::Error.for_item('file', @id, "'name' is empty") - end -+ if @file[:name].include?('/') -+ raise PcsdExchangeFormat::Error.for_item( -+ 'file', @id, "'name' cannot contain '/'" -+ ) -+ end - end - - def dir() --- -2.13.6 - diff --git a/SOURCES/bz1557253-03-use-rubygem-rack-protection-1.5.5.patch b/SOURCES/bz1557253-03-use-rubygem-rack-protection-1.5.5.patch deleted file mode 100644 index 511f687..0000000 --- a/SOURCES/bz1557253-03-use-rubygem-rack-protection-1.5.5.patch +++ /dev/null @@ -1,25 +0,0 @@ -From d9737919ae15880da163b768d223cf5149cb8cf4 Mon Sep 17 00:00:00 2001 -From: Ondrej Mular -Date: Wed, 21 Mar 2018 08:09:07 +0100 -Subject: [PATCH 3/3] use rubygem rack-protection 1.5.5 - ---- - pcsd/Gemfile.lock | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/pcsd/Gemfile.lock b/pcsd/Gemfile.lock -index fd5a8dcc..06bfa76c 100644 ---- a/pcsd/Gemfile.lock -+++ b/pcsd/Gemfile.lock -@@ -8,7 +8,7 @@ GEM - open4 (1.3.4) - orderedhash (0.0.6) - rack (1.6.4) -- rack-protection (1.5.3) -+ rack-protection (1.5.5) - rack - rack-test (0.7.0) - rack (>= 1.0) --- -2.13.6 - diff --git a/SOURCES/bz1572886-01-fix-syntax-multiple-except.-as-parenthes.-tuple.patch b/SOURCES/bz1572886-01-fix-syntax-multiple-except.-as-parenthes.-tuple.patch new file mode 100644 index 0000000..0d51b6c --- /dev/null +++ b/SOURCES/bz1572886-01-fix-syntax-multiple-except.-as-parenthes.-tuple.patch @@ -0,0 +1,30 @@ +From 19ad28a9be0344b8c0bcde7c711ecbf5062a95ea Mon Sep 17 00:00:00 2001 +From: Ivan Devat +Date: Mon, 6 Aug 2018 08:43:47 +0200 +Subject: [PATCH] fix syntax (multiple except. as parenthes. tuple) + +See https://docs.python.org/2/tutorial/errors.html#handling-exceptions + +...the parentheses around this tuple are required, because except +ValueError, e: was the syntax used for what is normally written as +except ValueError as e: in modern Python... +--- + pcs/cluster.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pcs/cluster.py b/pcs/cluster.py +index a64fd5fd..b4d49d27 100644 +--- a/pcs/cluster.py ++++ b/pcs/cluster.py +@@ -1138,7 +1138,7 @@ class IsComponentStartSupported(object): + data["pcsd_capabilities"] + ): + self.supported = True +- except KeyError, ValueError: ++ except (KeyError, ValueError): + # not a valid json or 404 => not supported + pass + +-- +2.13.6 + diff --git a/SOURCES/bz1599758-01-fix-node-communicator-getter.patch b/SOURCES/bz1599758-01-fix-node-communicator-getter.patch new file mode 100644 index 0000000..e10c4b6 --- /dev/null +++ b/SOURCES/bz1599758-01-fix-node-communicator-getter.patch @@ -0,0 +1,25 @@ +From 47400e6389452291ac44294181789665f90061d1 Mon Sep 17 00:00:00 2001 +From: Ivan Devat +Date: Mon, 6 Aug 2018 08:43:47 +0200 +Subject: [PATCH] fix node communicator getter + +--- + pcs/lib/env.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pcs/lib/env.py b/pcs/lib/env.py +index 46eb9467..86f67b64 100644 +--- a/pcs/lib/env.py ++++ b/pcs/lib/env.py +@@ -417,7 +417,7 @@ class LibraryEnvironment(object): + return NodeCommunicator( + self.logger, + self.report_processor, +- self.__get_auth_tokens(), ++ self.__get_token_file()["tokens"], + self.user_login, + self.user_groups, + self._request_timeout +-- +2.13.6 + diff --git a/SOURCES/bz1600169-01-disable-usage-of-Expect-HTTP-header.patch b/SOURCES/bz1600169-01-disable-usage-of-Expect-HTTP-header.patch new file mode 100644 index 0000000..23a0085 --- /dev/null +++ b/SOURCES/bz1600169-01-disable-usage-of-Expect-HTTP-header.patch @@ -0,0 +1,79 @@ +From 5df7d647e3cdb4b73e0bfd0a4fa83b78efd861f5 Mon Sep 17 00:00:00 2001 +From: Ivan Devat +Date: Mon, 6 Aug 2018 08:43:47 +0200 +Subject: [PATCH] disable usage of 'Expect' HTTP header + +--- + pcs/common/node_communicator.py | 1 + + pcs/lib/external.py | 1 + + pcs/test/tools/custom_mock.py | 4 ++++ + pcs/utils.py | 1 + + pcsd/pcs.rb | 1 + + 5 files changed, 8 insertions(+) + +diff --git a/pcs/common/node_communicator.py b/pcs/common/node_communicator.py +index f7fe2419..d54e8566 100644 +--- a/pcs/common/node_communicator.py ++++ b/pcs/common/node_communicator.py +@@ -532,6 +532,7 @@ def _create_request_handle(request, cookies, timeout): + handle.setopt(pycurl.SSL_VERIFYHOST, 0) + handle.setopt(pycurl.SSL_VERIFYPEER, 0) + handle.setopt(pycurl.NOSIGNAL, 1) # required for multi-threading ++ handle.setopt(pycurl.HTTPHEADER, ["Expect: "]) + if cookies: + handle.setopt( + pycurl.COOKIE, _dict_to_cookies(cookies).encode("utf-8") +diff --git a/pcs/lib/external.py b/pcs/lib/external.py +index fe17a864..e53a54ee 100644 +--- a/pcs/lib/external.py ++++ b/pcs/lib/external.py +@@ -620,6 +620,7 @@ class NodeCommunicator(object): + handler.setopt(pycurl.SSL_VERIFYHOST, 0) + handler.setopt(pycurl.SSL_VERIFYPEER, 0) + handler.setopt(pycurl.NOSIGNAL, 1) # required for multi-threading ++ handler.setopt(pycurl.HTTPHEADER, ["Expect: "]) + if cookies: + handler.setopt(pycurl.COOKIE, ";".join(cookies).encode("utf-8")) + if data: +diff --git a/pcs/test/tools/custom_mock.py b/pcs/test/tools/custom_mock.py +index c05a5a45..849f83fb 100644 +--- a/pcs/test/tools/custom_mock.py ++++ b/pcs/test/tools/custom_mock.py +@@ -75,6 +75,10 @@ class MockCurl(object): + self._opts = {} + + def setopt(self, opt, val): ++ if isinstance(val, list): ++ # in tests we use set operations (e.g. assertLessEqual) which ++ # require hashable values ++ val = tuple(val) + if val is None: + self.unsetopt(opt) + else: +diff --git a/pcs/utils.py b/pcs/utils.py +index 347ad73e..8a989f52 100644 +--- a/pcs/utils.py ++++ b/pcs/utils.py +@@ -498,6 +498,7 @@ def sendHTTPRequest( + handler.setopt(pycurl.TIMEOUT_MS, int(timeout * 1000)) + handler.setopt(pycurl.SSL_VERIFYHOST, 0) + handler.setopt(pycurl.SSL_VERIFYPEER, 0) ++ handler.setopt(pycurl.HTTPHEADER, ["Expect: "]) + if cookies: + handler.setopt(pycurl.COOKIE, ";".join(cookies).encode("utf-8")) + if data: +diff --git a/pcsd/pcs.rb b/pcsd/pcs.rb +index 66919c0c..ad153f62 100644 +--- a/pcsd/pcs.rb ++++ b/pcsd/pcs.rb +@@ -513,6 +513,7 @@ def send_request( + :httpget => (post ? 0 : 1), + :nosignal => 1, # required for multi-threading + }) ++ req.compose_header('Expect', '') + return_code = req.perform + if return_code == :ok + return req.response_code, req.response_body +-- +2.13.6 + diff --git a/SOURCES/bz1623181-01-fix-instance-attr-setting-for-OSP-agents.patch b/SOURCES/bz1623181-01-fix-instance-attr-setting-for-OSP-agents.patch new file mode 100644 index 0000000..dfe488e --- /dev/null +++ b/SOURCES/bz1623181-01-fix-instance-attr-setting-for-OSP-agents.patch @@ -0,0 +1,207 @@ +From b52c3ed9ec342b021357b915eaf6581f9f6a57d2 Mon Sep 17 00:00:00 2001 +From: Ondrej Mular +Date: Fri, 31 Aug 2018 10:12:18 +0200 +Subject: [PATCH] fix allowed instance attrs for some fence agents + +Fix is effective only for agents `fence_compute` and `fence_evacuate` +--- + pcs/lib/resource_agent.py | 22 ++++++++++++- + pcs/lib/test/test_resource_agent.py | 50 +++++++++++++++++++++++++++++ + pcs/test/test_stonith.py | 63 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 134 insertions(+), 1 deletion(-) + +diff --git a/pcs/lib/resource_agent.py b/pcs/lib/resource_agent.py +index 34b18b9b..447cf1fe 100644 +--- a/pcs/lib/resource_agent.py ++++ b/pcs/lib/resource_agent.py +@@ -469,6 +469,14 @@ class Agent(object): + "obsoletes": parameter_element.get("obsoletes", None), + }) + ++ def _get_always_allowed_parameters(self): ++ """ ++ This method should be overriden in descendants. ++ ++ Returns set of always allowed parameters of a agent. ++ """ ++ return set() ++ + def validate_parameters( + self, parameters, + parameters_type="resource", +@@ -518,13 +526,17 @@ class Agent(object): + agent_params = self.get_parameters() + + required_missing = [] ++ always_allowed = self._get_always_allowed_parameters() + for attr in agent_params: + if attr["required"] and attr["name"] not in parameters_values: + required_missing.append(attr["name"]) + + valid_attrs = [attr["name"] for attr in agent_params] + return ( +- [attr for attr in parameters_values if attr not in valid_attrs], ++ [ ++ attr for attr in parameters_values ++ if attr not in valid_attrs and attr not in always_allowed ++ ], + required_missing + ) + +@@ -858,6 +870,14 @@ class StonithAgent(CrmAgent): + self._get_stonithd_metadata().get_parameters() + ) + ++ def _get_always_allowed_parameters(self): ++ if self.get_name() in ("fence_compute", "fence_evacuate"): ++ return set([ ++ "project-domain", "project_domain", "user-domain", ++ "user_domain", "compute-domain", "compute_domain", ++ ]) ++ return set() ++ + def validate_parameters( + self, parameters, + parameters_type="stonith", +diff --git a/pcs/lib/test/test_resource_agent.py b/pcs/lib/test/test_resource_agent.py +index 4ec94e26..2396bf30 100644 +--- a/pcs/lib/test/test_resource_agent.py ++++ b/pcs/lib/test/test_resource_agent.py +@@ -1275,6 +1275,23 @@ class AgentMetadataValidateParametersValuesTest(TestCase): + (["obsoletes"], ["deprecated"]) + ) + ++ @patch_agent_object( ++ "_get_always_allowed_parameters", ++ lambda self: set(["always_allowed", "another-one", "last_one"]) ++ ) ++ def test_always_allowed(self, mock_metadata): ++ mock_metadata.return_value = self.metadata ++ self.assertEqual( ++ self.agent.validate_parameters_values({ ++ "another_required_param": "value1", ++ "required_param": "value2", ++ "test_param": "value3", ++ "always_allowed": "value4", ++ "another-one": "value5", ++ }), ++ ([], []) ++ ) ++ + + class AgentMetadataValidateParameters(TestCase): + def setUp(self): +@@ -2175,3 +2192,36 @@ class AbsentResourceAgentTest(TestCase): + self.assertEqual(([], []), absent.validate_parameters_values({ + "whatever": "anything" + })) ++ ++ ++class StonithAgentAlwaysAllowedParametersTest(TestCase): ++ def setUp(self): ++ self.runner = mock.MagicMock(spec_set=CommandRunner) ++ self.always_allowed = set([ ++ "project-domain", "project_domain", "user-domain", "user_domain", ++ "compute-domain", "compute_domain", ++ ]) ++ ++ def test_fence_compute(self): ++ self.assertEquals( ++ self.always_allowed, ++ lib_ra.StonithAgent( ++ self.runner, "fence_compute" ++ )._get_always_allowed_parameters() ++ ) ++ ++ def test_fence_evacuate(self): ++ self.assertEquals( ++ self.always_allowed, ++ lib_ra.StonithAgent( ++ self.runner, "fence_evacuate" ++ )._get_always_allowed_parameters() ++ ) ++ ++ def test_some_other_agent(self): ++ self.assertEquals( ++ set(), ++ lib_ra.StonithAgent( ++ self.runner, "fence_dummy" ++ )._get_always_allowed_parameters() ++ ) +diff --git a/pcs/test/test_stonith.py b/pcs/test/test_stonith.py +index cdb2ecee..ff981acc 100644 +--- a/pcs/test/test_stonith.py ++++ b/pcs/test/test_stonith.py +@@ -469,6 +469,69 @@ class StonithTest(TestCase, AssertPcsMixin): + ) + ) + ++ def test_stonith_compute_evacuate_always_allowed_parameters(self): ++ self.assert_pcs_success( ++ "stonith create test1 fence_compute auth_url=test1 project_domain=val1 project-domain=val2 user_domain=val3 user-domain=val4 compute_domain=val5 compute-domain=val6", ++ ) ++ self.assert_pcs_success( ++ "stonith show --full", ++ outdent( ++ """\ ++ Resource: test1 (class=stonith type=fence_compute) ++ Attributes: auth_url=test1 compute-domain=val6 compute_domain=val5 project-domain=val2 project_domain=val1 user-domain=val4 user_domain=val3 ++ Operations: monitor interval=60s (test1-monitor-interval-60s) ++ """ ++ ) ++ ) ++ self.assert_pcs_success( ++ "stonith create test2 fence_evacuate auth_url=test2 project_domain=val0 project-domain=val1 user_domain=val2 user-domain=val3 compute_domain=val4 compute-domain=val5", ++ ) ++ self.assert_pcs_success( ++ "stonith show --full", ++ outdent( ++ """\ ++ Resource: test1 (class=stonith type=fence_compute) ++ Attributes: auth_url=test1 compute-domain=val6 compute_domain=val5 project-domain=val2 project_domain=val1 user-domain=val4 user_domain=val3 ++ Operations: monitor interval=60s (test1-monitor-interval-60s) ++ Resource: test2 (class=stonith type=fence_evacuate) ++ Attributes: auth_url=test2 compute-domain=val5 compute_domain=val4 project-domain=val1 project_domain=val0 user-domain=val3 user_domain=val2 ++ Operations: monitor interval=60s (test2-monitor-interval-60s) ++ """ ++ ) ++ ) ++ self.assert_pcs_success( ++ "stonith update test1 auth_url=new0 project_domain=new1 project-domain=new2 user_domain=new3 user-domain=new4 compute_domain=new5 compute-domain=new6", ++ ) ++ self.assert_pcs_success( ++ "stonith show --full", ++ outdent( ++ """\ ++ Resource: test1 (class=stonith type=fence_compute) ++ Attributes: auth_url=new0 compute-domain=new6 compute_domain=new5 project-domain=new2 project_domain=new1 user-domain=new4 user_domain=new3 ++ Operations: monitor interval=60s (test1-monitor-interval-60s) ++ Resource: test2 (class=stonith type=fence_evacuate) ++ Attributes: auth_url=test2 compute-domain=val5 compute_domain=val4 project-domain=val1 project_domain=val0 user-domain=val3 user_domain=val2 ++ Operations: monitor interval=60s (test2-monitor-interval-60s) ++ """ ++ ) ++ ) ++ self.assert_pcs_success( ++ "stonith update test2 auth_url=new1 project_domain=new2 project-domain=new3 user_domain=new4 user-domain=new5 compute_domain=new6 compute-domain=new7", ++ ) ++ self.assert_pcs_success( ++ "stonith show --full", ++ outdent( ++ """\ ++ Resource: test1 (class=stonith type=fence_compute) ++ Attributes: auth_url=new0 compute-domain=new6 compute_domain=new5 project-domain=new2 project_domain=new1 user-domain=new4 user_domain=new3 ++ Operations: monitor interval=60s (test1-monitor-interval-60s) ++ Resource: test2 (class=stonith type=fence_evacuate) ++ Attributes: auth_url=new1 compute-domain=new7 compute_domain=new6 project-domain=new3 project_domain=new2 user-domain=new5 user_domain=new4 ++ Operations: monitor interval=60s (test2-monitor-interval-60s) ++ """ ++ ) ++ ) ++ + def testStonithFenceConfirm(self): + output, returnVal = pcs(temp_cib, "stonith fence blah blah") + assert returnVal == 1 +-- +2.13.6 + diff --git a/SOURCES/bz1628070-01-fix-instance-attr-setting-for-OSP-agents.patch b/SOURCES/bz1628070-01-fix-instance-attr-setting-for-OSP-agents.patch deleted file mode 100644 index e2617aa..0000000 --- a/SOURCES/bz1628070-01-fix-instance-attr-setting-for-OSP-agents.patch +++ /dev/null @@ -1,207 +0,0 @@ -From 1ac934ffe7b17bb5a4248e8b2f293815b0bb8a68 Mon Sep 17 00:00:00 2001 -From: Ondrej Mular -Date: Fri, 31 Aug 2018 10:12:18 +0200 -Subject: [PATCH] fix allowed instance attrs for some fence agents - -Fix is effective only for agents `fence_compute` and `fence_evacuate` ---- - pcs/lib/resource_agent.py | 22 ++++++++++++- - pcs/lib/test/test_resource_agent.py | 50 +++++++++++++++++++++++++++++ - pcs/test/test_stonith.py | 63 +++++++++++++++++++++++++++++++++++++ - 3 files changed, 134 insertions(+), 1 deletion(-) - -diff --git a/pcs/lib/resource_agent.py b/pcs/lib/resource_agent.py -index 2f2686dd..e2461329 100644 ---- a/pcs/lib/resource_agent.py -+++ b/pcs/lib/resource_agent.py -@@ -469,6 +469,14 @@ class Agent(object): - "obsoletes": parameter_element.get("obsoletes", None), - }) - -+ def _get_always_allowed_parameters(self): -+ """ -+ This method should be overriden in descendants. -+ -+ Returns set of always allowed parameters of a agent. -+ """ -+ return set() -+ - def validate_parameters( - self, parameters, - parameters_type="resource", -@@ -518,13 +526,17 @@ class Agent(object): - agent_params = self.get_parameters() - - required_missing = [] -+ always_allowed = self._get_always_allowed_parameters() - for attr in agent_params: - if attr["required"] and attr["name"] not in parameters_values: - required_missing.append(attr["name"]) - - valid_attrs = [attr["name"] for attr in agent_params] - return ( -- [attr for attr in parameters_values if attr not in valid_attrs], -+ [ -+ attr for attr in parameters_values -+ if attr not in valid_attrs and attr not in always_allowed -+ ], - required_missing - ) - -@@ -858,6 +870,14 @@ class StonithAgent(CrmAgent): - self._get_stonithd_metadata().get_parameters() - ) - -+ def _get_always_allowed_parameters(self): -+ if self.get_name() in ("fence_compute", "fence_evacuate"): -+ return set([ -+ "project-domain", "project_domain", "user-domain", -+ "user_domain", "compute-domain", "compute_domain", -+ ]) -+ return set() -+ - def validate_parameters( - self, parameters, - parameters_type="stonith", -diff --git a/pcs/lib/test/test_resource_agent.py b/pcs/lib/test/test_resource_agent.py -index a8be5fcd..ea579ad4 100644 ---- a/pcs/lib/test/test_resource_agent.py -+++ b/pcs/lib/test/test_resource_agent.py -@@ -1275,6 +1275,23 @@ class AgentMetadataValidateParametersValuesTest(TestCase): - (["obsoletes"], ["deprecated"]) - ) - -+ @patch_agent_object( -+ "_get_always_allowed_parameters", -+ lambda self: set(["always_allowed", "another-one", "last_one"]) -+ ) -+ def test_always_allowed(self, mock_metadata): -+ mock_metadata.return_value = self.metadata -+ self.assertEqual( -+ self.agent.validate_parameters_values({ -+ "another_required_param": "value1", -+ "required_param": "value2", -+ "test_param": "value3", -+ "always_allowed": "value4", -+ "another-one": "value5", -+ }), -+ ([], []) -+ ) -+ - - class AgentMetadataValidateParameters(TestCase): - def setUp(self): -@@ -2175,3 +2192,36 @@ class AbsentResourceAgentTest(TestCase): - self.assertEqual(([], []), absent.validate_parameters_values({ - "whatever": "anything" - })) -+ -+ -+class StonithAgentAlwaysAllowedParametersTest(TestCase): -+ def setUp(self): -+ self.runner = mock.MagicMock(spec_set=CommandRunner) -+ self.always_allowed = set([ -+ "project-domain", "project_domain", "user-domain", "user_domain", -+ "compute-domain", "compute_domain", -+ ]) -+ -+ def test_fence_compute(self): -+ self.assertEquals( -+ self.always_allowed, -+ lib_ra.StonithAgent( -+ self.runner, "fence_compute" -+ )._get_always_allowed_parameters() -+ ) -+ -+ def test_fence_evacuate(self): -+ self.assertEquals( -+ self.always_allowed, -+ lib_ra.StonithAgent( -+ self.runner, "fence_evacuate" -+ )._get_always_allowed_parameters() -+ ) -+ -+ def test_some_other_agent(self): -+ self.assertEquals( -+ set(), -+ lib_ra.StonithAgent( -+ self.runner, "fence_dummy" -+ )._get_always_allowed_parameters() -+ ) -diff --git a/pcs/test/test_stonith.py b/pcs/test/test_stonith.py -index becc1a1c..b7c964bb 100644 ---- a/pcs/test/test_stonith.py -+++ b/pcs/test/test_stonith.py -@@ -469,6 +469,69 @@ class StonithTest(TestCase, AssertPcsMixin): - ) - ) - -+ def test_stonith_compute_evacuate_always_allowed_parameters(self): -+ self.assert_pcs_success( -+ "stonith create test1 fence_compute auth_url=test1 project_domain=val1 project-domain=val2 user_domain=val3 user-domain=val4 compute_domain=val5 compute-domain=val6", -+ ) -+ self.assert_pcs_success( -+ "stonith show --full", -+ outdent( -+ """\ -+ Resource: test1 (class=stonith type=fence_compute) -+ Attributes: auth_url=test1 compute-domain=val6 compute_domain=val5 project-domain=val2 project_domain=val1 user-domain=val4 user_domain=val3 -+ Operations: monitor interval=60s (test1-monitor-interval-60s) -+ """ -+ ) -+ ) -+ self.assert_pcs_success( -+ "stonith create test2 fence_evacuate auth_url=test2 project_domain=val0 project-domain=val1 user_domain=val2 user-domain=val3 compute_domain=val4 compute-domain=val5", -+ ) -+ self.assert_pcs_success( -+ "stonith show --full", -+ outdent( -+ """\ -+ Resource: test1 (class=stonith type=fence_compute) -+ Attributes: auth_url=test1 compute-domain=val6 compute_domain=val5 project-domain=val2 project_domain=val1 user-domain=val4 user_domain=val3 -+ Operations: monitor interval=60s (test1-monitor-interval-60s) -+ Resource: test2 (class=stonith type=fence_evacuate) -+ Attributes: auth_url=test2 compute-domain=val5 compute_domain=val4 project-domain=val1 project_domain=val0 user-domain=val3 user_domain=val2 -+ Operations: monitor interval=60s (test2-monitor-interval-60s) -+ """ -+ ) -+ ) -+ self.assert_pcs_success( -+ "stonith update test1 auth_url=new0 project_domain=new1 project-domain=new2 user_domain=new3 user-domain=new4 compute_domain=new5 compute-domain=new6", -+ ) -+ self.assert_pcs_success( -+ "stonith show --full", -+ outdent( -+ """\ -+ Resource: test1 (class=stonith type=fence_compute) -+ Attributes: auth_url=new0 compute-domain=new6 compute_domain=new5 project-domain=new2 project_domain=new1 user-domain=new4 user_domain=new3 -+ Operations: monitor interval=60s (test1-monitor-interval-60s) -+ Resource: test2 (class=stonith type=fence_evacuate) -+ Attributes: auth_url=test2 compute-domain=val5 compute_domain=val4 project-domain=val1 project_domain=val0 user-domain=val3 user_domain=val2 -+ Operations: monitor interval=60s (test2-monitor-interval-60s) -+ """ -+ ) -+ ) -+ self.assert_pcs_success( -+ "stonith update test2 auth_url=new1 project_domain=new2 project-domain=new3 user_domain=new4 user-domain=new5 compute_domain=new6 compute-domain=new7", -+ ) -+ self.assert_pcs_success( -+ "stonith show --full", -+ outdent( -+ """\ -+ Resource: test1 (class=stonith type=fence_compute) -+ Attributes: auth_url=new0 compute-domain=new6 compute_domain=new5 project-domain=new2 project_domain=new1 user-domain=new4 user_domain=new3 -+ Operations: monitor interval=60s (test1-monitor-interval-60s) -+ Resource: test2 (class=stonith type=fence_evacuate) -+ Attributes: auth_url=new1 compute-domain=new7 compute_domain=new6 project-domain=new3 project_domain=new2 user-domain=new5 user_domain=new4 -+ Operations: monitor interval=60s (test2-monitor-interval-60s) -+ """ -+ ) -+ ) -+ - def testStonithFenceConfirm(self): - output, returnVal = pcs(temp_cib, "stonith fence blah blah") - assert returnVal == 1 --- -2.13.6 - diff --git a/SOURCES/change-cman-to-rhel6-in-messages.patch b/SOURCES/change-cman-to-rhel6-in-messages.patch index 96a6019..928ca1b 100644 --- a/SOURCES/change-cman-to-rhel6-in-messages.patch +++ b/SOURCES/change-cman-to-rhel6-in-messages.patch @@ -1,26 +1,26 @@ -From 0f462859f1a923093f211ea9813b8147f00be431 Mon Sep 17 00:00:00 2001 +From 584e0e4d16e7e811aaac24f0db11bf59c909b895 Mon Sep 17 00:00:00 2001 From: Ivan Devat Date: Mon, 23 May 2016 17:00:13 +0200 -Subject: [PATCH] change cman to rhel6 in messages +Subject: [PATCH 4/5] change cman to rhel6 in messages --- pcs/cli/common/console_report.py | 8 ++++---- pcs/cluster.py | 6 +++--- pcs/config.py | 2 +- - pcs/pcs.8 | 10 +++++----- + pcs/pcs.8 | 12 ++++++------ pcs/quorum.py | 2 +- pcs/test/test_cluster.py | 26 +++++++++++++------------- pcs/usage.py | 20 ++++++++++---------- pcsd/views/_dialogs.erb | 2 +- pcsd/views/manage.erb | 16 ++++++++-------- pcsd/views/nodes.erb | 2 +- - 10 files changed, 47 insertions(+), 47 deletions(-) + 10 files changed, 48 insertions(+), 48 deletions(-) diff --git a/pcs/cli/common/console_report.py b/pcs/cli/common/console_report.py -index 406532dd..75fcf562 100644 +index 06ea8f72..973b2cbb 100644 --- a/pcs/cli/common/console_report.py +++ b/pcs/cli/common/console_report.py -@@ -642,7 +642,7 @@ CODE_TO_MESSAGE_BUILDER_MAP = { +@@ -676,7 +676,7 @@ CODE_TO_MESSAGE_BUILDER_MAP = { , codes.CMAN_UNSUPPORTED_COMMAND: @@ -29,7 +29,7 @@ index 406532dd..75fcf562 100644 , codes.ID_ALREADY_EXISTS: lambda info: -@@ -889,7 +889,7 @@ CODE_TO_MESSAGE_BUILDER_MAP = { +@@ -932,7 +932,7 @@ CODE_TO_MESSAGE_BUILDER_MAP = { , codes.IGNORED_CMAN_UNSUPPORTED_OPTION: lambda info: @@ -38,7 +38,7 @@ index 406532dd..75fcf562 100644 .format(**info) , -@@ -898,12 +898,12 @@ CODE_TO_MESSAGE_BUILDER_MAP = { +@@ -941,12 +941,12 @@ CODE_TO_MESSAGE_BUILDER_MAP = { , codes.CMAN_UDPU_RESTART_REQUIRED: ( @@ -54,10 +54,10 @@ index 406532dd..75fcf562 100644 ), diff --git a/pcs/cluster.py b/pcs/cluster.py -index a3cc74c6..ecafa756 100644 +index c2af8a8f..7d13e11e 100644 --- a/pcs/cluster.py +++ b/pcs/cluster.py -@@ -1938,7 +1938,7 @@ def node_add(lib_env, node0, node1, modifiers): +@@ -2105,7 +2105,7 @@ def node_add(lib_env, node0, node1, modifiers): else: utils.err("Unable to update any nodes") if utils.is_cman_with_udpu_transport(): @@ -66,7 +66,7 @@ index a3cc74c6..ecafa756 100644 + "cluster restart is required to apply node addition") if wait: print() -@@ -2014,7 +2014,7 @@ def node_remove(lib_env, node0, modifiers): +@@ -2181,7 +2181,7 @@ def node_remove(lib_env, node0, modifiers): output, retval = utils.reloadCorosync() output, retval = utils.run(["crm_node", "--force", "-R", node0]) if utils.is_cman_with_udpu_transport(): @@ -75,7 +75,7 @@ index a3cc74c6..ecafa756 100644 + "cluster restart is required to apply node removal") def cluster_localnode(argv): -@@ -2182,7 +2182,7 @@ def cluster_uidgid(argv, silent_list = False): +@@ -2349,7 +2349,7 @@ def cluster_uidgid(argv, silent_list = False): def cluster_get_corosync_conf(argv): if utils.is_rhel6(): @@ -85,7 +85,7 @@ index a3cc74c6..ecafa756 100644 if len(argv) > 1: usage.cluster() diff --git a/pcs/config.py b/pcs/config.py -index ac32b669..450403c0 100644 +index 11ddb901..747d1b24 100644 --- a/pcs/config.py +++ b/pcs/config.py @@ -613,7 +613,7 @@ def config_checkpoint_restore(argv): @@ -98,27 +98,28 @@ index ac32b669..450403c0 100644 cluster_conf = settings.cluster_conf_file dry_run_output = None diff --git a/pcs/pcs.8 b/pcs/pcs.8 -index 15454c7f..02eab591 100644 +index 8b1ed840..3bf6d553 100644 --- a/pcs/pcs.8 +++ b/pcs/pcs.8 @@ -209,13 +209,13 @@ auth [[:]] [...] [\fB\-u\fR ] [\fB\-p\fR ] [\fB\ Authenticate pcs to pcsd on nodes specified, or on all nodes configured in the local cluster if no nodes are specified (authorization tokens are stored in ~/.pcs/tokens or /var/lib/pcsd/tokens for root). By default all nodes are also authenticated to each other, using \fB\-\-local\fR only authenticates the local node (and does not authenticate the remote nodes with each other). Using \fB\-\-force\fR forces re\-authentication to occur. .TP - setup [\fB\-\-start\fR [\fB\-\-wait\fR[=]]] [\fB\-\-local\fR] [\fB\-\-enable\fR] \fB\-\-name\fR [] [...] [\fB\-\-transport\fR udpu|udp] [\fB\-\-rrpmode\fR active|passive] [\fB\-\-addr0\fR [[[\fB\-\-mcast0\fR
] [\fB\-\-mcastport0\fR ] [\fB\-\-ttl0\fR ]] | [\fB\-\-broadcast0\fR]] [\fB\-\-addr1\fR [[[\fB\-\-mcast1\fR
] [\fB\-\-mcastport1\fR ] [\fB\-\-ttl1\fR ]] | [\fB\-\-broadcast1\fR]]]] [\fB\-\-wait_for_all\fR=<0|1>] [\fB\-\-auto_tie_breaker\fR=<0|1>] [\fB\-\-last_man_standing\fR=<0|1> [\fB\-\-last_man_standing_window\fR=