Skip to content

Commit 29eb2b1

Browse files
author
Nelson Goncalves
committed
BUG#26830224: DBA.CONFIGURELOCALINSTANCE() CLAIMS STATUS IS OK WHEN MY.CNF UPDATE FAILED
When using the configureLocalInstance command to update the configuration file of a server already belonging to a cluster no error message would be displayed if the user didn't have enough file system privileges to update the configuration file. This patch fixes that issue and now, an appropriate error message is shown in the output if the user is lacking privileges to update the configuration file. Furthermore, some test related code was moved. A new test was added to verify the new behavior, although it only runs on Unix systems.
1 parent d1112c9 commit 29eb2b1

File tree

8 files changed

+77
-23
lines changed

8 files changed

+77
-23
lines changed

python/front_end/mysqlprovision.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,10 @@
877877
command_error_msg = "executing operation"
878878
try:
879879
if command == CHECK:
880-
command_error_msg = "checking instance"
880+
if cmd_options.get("update", False):
881+
command_error_msg = "configuring instance"
882+
else:
883+
command_error_msg = "checking instance"
881884
check(**cmd_options)
882885

883886
elif command == CLONE:

python/mysql_gadgets/command/gr_admin.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,7 @@ def check(**kwargs):
299299
_LOGGER.info("Updating option file '%s' with Group "
300300
"Replication settings from "
301301
"%s", option_file, str(server))
302-
persist_gr_config(option_file, gr_configs)
303-
result = True
302+
result = persist_gr_config(option_file, gr_configs)
304303
else:
305304
result = False
306305
# If the server doesn't belong to any group, check if it meets GR

python/mysql_gadgets/common/config_parser.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
33
#
44
# This program is free software; you can redistribute it and/or modify
55
# it under the terms of the GNU General Public License as published by
@@ -434,7 +434,7 @@ def __init__(self, filename): # pylint: disable=W0231
434434

435435
self.default_extension = DEFAULT_EXTENSIONS[os.name]
436436
# get the absolute path for the provided filename
437-
self.filename = get_abs_path(filename, os.getcwd())
437+
self.filename = os.path.normpath(get_abs_path(filename, os.getcwd()))
438438
self._parse_option_file(self.filename)
439439

440440
# Convert all section names to lower case.
@@ -495,8 +495,8 @@ def _parse_option_file(self, filename):
495495
files.insert(len(files), filename)
496496
except (IOError, OSError) as err:
497497
raise GadgetConfigParserError(
498-
"Option file '{0}' is not readable: "
499-
"'{1}'".format(self.filename, str(err)),
498+
"Option file '{0}' is not readable."
499+
"".format(self.filename),
500500
cause=err)
501501

502502
# Read configurations from option files.
@@ -858,23 +858,23 @@ def optval_tostr(opt, val):
858858
lines = f.readlines()
859859
except IOError as err:
860860
raise GadgetConfigParserError(
861-
"Option file '{0}' is not readable: "
862-
"'{1}'".format(self.filename, str(err)),
861+
"Option file '{0}' is not readable."
862+
"".format(self.filename),
863863
cause=err)
864864
# Create a backup file if provided
865865
if backup_file_path:
866866
if not os.path.isabs(backup_file_path):
867867
raise GadgetConfigParserError(
868868
"'{0}' is not an absolute path. Please provide an "
869-
"absolute path to the backup file")
869+
"absolute path to the backup file".format(backup_file_path))
870870
else:
871871
try:
872872
with open(backup_file_path, 'w') as bf:
873873
bf.writelines(lines)
874874
except IOError as err:
875875
raise GadgetConfigParserError(
876-
"Backup file '{0}' is not writable: "
877-
"'{1}'".format(backup_file_path, str(err)),
876+
"Backup file '{0}' is not writable."
877+
"".format(backup_file_path),
878878
cause=err)
879879
f = None
880880
try:
@@ -1002,8 +1002,8 @@ def optval_tostr(opt, val):
10021002
f.write("{0}\n".format(optval_tostr(opt, val)))
10031003
except IOError as err:
10041004
raise GadgetConfigParserError(
1005-
"Option file '{0}' is not writable: "
1006-
"'{1}'".format(self.filename, str(err)),
1005+
"Option file '{0}' is not writable."
1006+
"".format(self.filename),
10071007
cause=err)
10081008
else:
10091009
# we've written changes to file, reset modified flag

python/mysql_gadgets/common/group_replication.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -835,9 +835,6 @@ def update_option_file(opt_parser, missing_values, update_values,
835835
dic_msg = str(update_values)
836836
dic_msg = dic_msg.replace("\\\\", "\\")
837837
_LOGGER.debug("update_values %s", dic_msg)
838-
# Verify option parser can update file
839-
if not os.access(opt_parser.filename, os.W_OK):
840-
return False
841838

842839
# Create the section if does not exist already
843840
if not opt_parser.has_section(MYSQLD_SECTION):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//@<OUT> Error no write privileges
2+
var cnfPath = __sandbox_dir + __mysql_sandbox_port1 + "/my.cnf";
3+
dba.configureLocalInstance('root@localhost:' + __mysql_sandbox_port1, {mycnfPath:cnfPath, password:'root'});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//@<OUT> Error no write privileges
2+
{
3+
"errors": [
4+
"Error configuring instance: Option file '<<<__output_sandbox_dir>>><<<__mysql_sandbox_port1>>><<<__path_splitter>>>my.cnf' is not writable."
5+
],
6+
"restart_required": false,
7+
"status": "error"
8+
}

unittest/shell_js_dba_t.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
* 02110-1301 USA
1818
*/
1919

20+
#ifdef _WIN32
21+
#include <windows.h>
22+
#endif
23+
2024
#include <algorithm>
2125
#include "modules/adminapi/mod_dba_sql.h"
2226
#include "modules/base_session.h"
@@ -477,6 +481,46 @@ TEST_F(Shell_js_dba_tests, configure_local_instance) {
477481
execute("cleanup_sandboxes(true)");
478482
}
479483

484+
TEST_F(Shell_js_dba_tests, configure_local_instance_errors) {
485+
_options->wizards = false;
486+
reset_shell();
487+
488+
// Execute setup script to be able to use smart deployment functions.
489+
execute_setup();
490+
491+
// Clean and delete all sandboxes.
492+
execute("cleanup_sandbox(__mysql_sandbox_port1);");
493+
494+
// Deploy new sandbox instance (required for this test).
495+
execute(
496+
"var deployed_here = reset_or_deploy_sandbox(__mysql_sandbox_port1);");
497+
498+
// create Cluster
499+
execute(
500+
"shell.connect({scheme: 'mysql', host: localhost, port: "
501+
"__mysql_sandbox_port1, user: 'root', password: 'root'});");
502+
execute("var cluster = dba.createCluster('Cluster')");
503+
504+
#ifndef _WIN32
505+
// Set permissions on configuration file to 444 (chmod only works on
506+
// unix systems).
507+
chmod(_sandbox_cnf_1.c_str(), S_IRUSR | S_IRGRP | S_IROTH);
508+
#else
509+
auto dwAttrs = GetFileAttributes(_sandbox_cnf_1.c_str());
510+
// set permissions on configuration file to read only
511+
SetFileAttributes(_sandbox_cnf_1.c_str(), dwAttrs | FILE_ATTRIBUTE_READONLY);
512+
#endif
513+
validate_interactive("dba_configure_local_instance_errors.js");
514+
515+
#ifdef _WIN32
516+
// Restore original permissions of configuration file
517+
SetFileAttributes(_sandbox_cnf_1.c_str(), dwAttrs);
518+
#endif
519+
// Cleans up the used sandbox
520+
execute("cleanup_sandbox(__mysql_sandbox_port1)");
521+
}
522+
523+
480524
TEST_F(Shell_js_dba_tests, force_quorum) {
481525
_options->wizards = false;
482526
reset_shell();

unittest/test_utils/shell_base_test.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include <fstream>
1717
#include <boost/algorithm/string.hpp>
18+
#include <utils/utils_path.h>
1819
#include "unittest/test_utils/shell_base_test.h"
1920
#include "shellcore/types.h"
2021
#include "utils/utils_general.h"
@@ -100,16 +101,15 @@ void Shell_base_test::SetUp() {
100101
_sandbox_dir = shcore::get_binary_folder();
101102
}
102103
}
103-
104-
std::vector<std::string> path_components = {_sandbox_dir,
105-
_mysql_sandbox_port1, "my.cnf"};
106-
_sandbox_cnf_1 = shcore::join_strings(path_components, _path_splitter);
104+
std::vector<std::string> path_components {_sandbox_dir,
105+
_mysql_sandbox_port1, "my.cnf"};
106+
_sandbox_cnf_1 = shcore::join_path(path_components);
107107

108108
path_components[1] = _mysql_sandbox_port2;
109-
_sandbox_cnf_2 = shcore::join_strings(path_components, _path_splitter);
109+
_sandbox_cnf_2 = shcore::join_path(path_components);
110110

111111
path_components[1] = _mysql_sandbox_port3;
112-
_sandbox_cnf_3 = shcore::join_strings(path_components, _path_splitter);
112+
_sandbox_cnf_3 = shcore::join_path(path_components);
113113

114114
_new_line_char = "\n";
115115
#ifdef WIN32

0 commit comments

Comments
 (0)