19
19
20
20
#include < string>
21
21
#include < random>
22
+ #include < mysqld_error.h>
23
+
24
+
22
25
#ifndef WIN32
23
26
#include < sys/un.h>
24
27
#endif
@@ -1588,6 +1591,12 @@ shcore::Value::Map_type_ref Dba::_check_instance_configuration(const shcore::Arg
1588
1591
shcore::Value::Map_type_ref validate_options;
1589
1592
1590
1593
std::string cnfpath, cluster_admin, cluster_admin_password;
1594
+ std::string admin_user, admin_user_host, validate_user, validate_host;
1595
+ std::string current_user, current_host, account_type, error_msg_extra;
1596
+ std::string uri_user = instance_def->get_string (
1597
+ instance_def->has_key (" user" ) ? " user" : " dbUser" );
1598
+ std::string uri_host = instance_def->get_string (" host" );
1599
+ bool cluster_admin_user_exists = false ;
1591
1600
bool clear_read_only = false ;
1592
1601
1593
1602
if (args.size () == 2 ) {
@@ -1632,18 +1641,80 @@ shcore::Value::Map_type_ref Dba::_check_instance_configuration(const shcore::Arg
1632
1641
new_args.push_back (shcore::Value (instance_def));
1633
1642
auto session = Dba::get_session (new_args);
1634
1643
1644
+ // get the current user
1645
+ auto result = session->execute_sql (" SELECT CURRENT_USER()" );
1646
+ auto row = result->fetch_one ();
1647
+ std::string current_account = row->get_value (0 ).as_string ();
1648
+ split_account (current_account, ¤t_user, ¤t_host);
1649
+
1650
+ // if this is a configureLocalInstance operation and the clusterAdmin
1651
+ // option was used and that user exists, validate its privileges, otherwise
1652
+ // validate the privileges of the current user
1653
+ if (allow_update && !cluster_admin.empty ()) {
1654
+ shcore::split_account (cluster_admin, &admin_user, &admin_user_host);
1655
+ // Host '%' is used by default if not provided in the user account.
1656
+ if (admin_user_host.empty ())
1657
+ admin_user_host = " %" ;
1658
+ // Check if the cluster_admin user exists
1659
+ shcore::sqlstring query = shcore::sqlstring (
1660
+ " SELECT COUNT(*) from mysql.user WHERE "
1661
+ " User = ? AND Host = ?" , 0 );
1662
+ query << admin_user << admin_user_host;
1663
+ query.done ();
1664
+ try {
1665
+ auto result = session->execute_sql (query);
1666
+ cluster_admin_user_exists =
1667
+ result->fetch_one ()->get_value (0 ).as_int () != 0 ;
1668
+ } catch (shcore::Exception &err) {
1669
+ if (err.code () == ER_TABLEACCESS_DENIED_ERROR) {
1670
+ // the current_account doesn't have enough privileges to execute
1671
+ // the query
1672
+ std::string error_msg;
1673
+ if (uri_host != current_host || uri_user != current_user)
1674
+ error_msg =
1675
+ " Session account '" + current_user + " '@'" + current_host +
1676
+ " '(used to authenticate '" + uri_user + " '@'" + uri_host +
1677
+ " ') does not have all the required privileges to execute this "
1678
+ " operation. For more information, see the online documentation." ;
1679
+ else
1680
+ error_msg =
1681
+ " Session account '" + current_user + " '@'" + current_host +
1682
+ " ' does not have all the required privileges to execute this "
1683
+ " operation. For more information, see the online documentation." ;
1684
+ log_error (" %s" , error_msg.c_str ());
1685
+ throw std::runtime_error (error_msg);
1686
+ } else {
1687
+ throw ;
1688
+ }
1689
+ }
1690
+ }
1691
+ if (cluster_admin_user_exists) {
1692
+ // cluster admin account exists, so we will validate its privileges
1693
+ validate_user = admin_user;
1694
+ validate_host = admin_user_host;
1695
+ account_type = " Cluster Admin" ;
1696
+ } else {
1697
+ // cluster admin doesn't exist, so we validate the privileges of the
1698
+ // current user
1699
+ validate_user = current_user;
1700
+ validate_host = current_host;
1701
+ account_type = " Session" ;
1702
+ if (uri_host != current_host || uri_user != current_user)
1703
+ error_msg_extra =
1704
+ " (used to authenticate '" + uri_user + " '@'" + uri_host + " ')" ;
1705
+ }
1635
1706
// Validate the permissions of the user running the operation.
1636
- if (!validate_cluster_admin_user_privileges (session, session-> get_user () ,
1637
- session-> get_host () )) {
1707
+ if (!validate_cluster_admin_user_privileges (session, validate_user ,
1708
+ validate_host )) {
1638
1709
std::string error_msg =
1639
- " Account '" + session->get_user () + " '@'" +
1640
- session->get_host () +
1641
- " ' does not have all the required privileges to execute this "
1642
- " operation. For more information, see the online documentation." ;
1710
+ account_type + " account '" + validate_user + " '@'" + validate_host +
1711
+ " '" + error_msg_extra +
1712
+ " does not have all the required privileges to "
1713
+ " execute this operation. For more information, see the online "
1714
+ " documentation." ;
1643
1715
log_error (" %s" , error_msg.c_str ());
1644
1716
throw std::runtime_error (error_msg);
1645
1717
}
1646
-
1647
1718
// Now validates the instance GR status itself
1648
1719
std::string uri = session->uri ();
1649
1720
@@ -1658,8 +1729,7 @@ shcore::Value::Map_type_ref Dba::_check_instance_configuration(const shcore::Arg
1658
1729
else if (type == GRInstanceType::InnoDBCluster && !allow_update) {
1659
1730
session->close (shcore::Argument_list ());
1660
1731
throw shcore::Exception::runtime_error (" The instance '" + uri + " ' is already part of an InnoDB Cluster" );
1661
- }
1662
- else {
1732
+ } else {
1663
1733
if (!cluster_admin.empty () && allow_update) {
1664
1734
auto classic =
1665
1735
dynamic_cast <mysqlsh::mysql::ClassicSession*>(session.get ());
@@ -1669,39 +1739,16 @@ shcore::Value::Map_type_ref Dba::_check_instance_configuration(const shcore::Arg
1669
1739
// and right before some execution failure of the command leaving the
1670
1740
// instance in an incorrect state
1671
1741
bool super_read_only = validate_super_read_only (classic, clear_read_only);
1672
-
1673
- try {
1674
- create_cluster_admin_user (session,
1675
- cluster_admin,
1676
- cluster_admin_password);
1677
- } catch (shcore::Exception &err) {
1678
- // Catch ER_CANNOT_USER (1396) if the user already exists, and skip it
1679
- // if the user has the needed privileges.
1680
- if (err.code () == ER_CANNOT_USER) {
1681
- std::string admin_user, admin_user_host;
1682
- shcore::split_account (cluster_admin, &admin_user, &admin_user_host);
1683
- // Host '%' is used by default if not provided in the user account.
1684
- if (admin_user_host.empty ())
1685
- admin_user_host = " %" ;
1686
- if (!validate_cluster_admin_user_privileges (session, admin_user,
1687
- admin_user_host)) {
1688
- std::string error_msg =
1689
- " User " + cluster_admin + " already exists but it does not "
1690
- " have all the privileges for managing an InnoDB cluster. "
1691
- " Please provide a non-existing user to be created or a "
1692
- " different one with all the required privileges." ;
1693
- errors->push_back (shcore::Value (error_msg));
1694
- log_error (" %s" , error_msg.c_str ());
1695
- } else {
1696
- log_warning (" User %s already exists." , cluster_admin.c_str ());
1697
- }
1698
- } else {
1742
+ if (!cluster_admin_user_exists) {
1743
+ try {
1744
+ create_cluster_admin_user (session, cluster_admin,
1745
+ cluster_admin_password);
1746
+ } catch (shcore::Exception &err) {
1699
1747
std::string error_msg = " Unexpected error creating " + cluster_admin +
1700
1748
" user: " + err.what ();
1701
1749
errors->push_back (shcore::Value (error_msg));
1702
1750
log_error (" %s" , error_msg.c_str ());
1703
1751
}
1704
-
1705
1752
// If we disabled super_read_only we must enable it back
1706
1753
// also confirm that the initial status was 1/ON
1707
1754
if (clear_read_only && super_read_only) {
@@ -1710,12 +1757,12 @@ shcore::Value::Map_type_ref Dba::_check_instance_configuration(const shcore::Arg
1710
1757
session_address.c_str ());
1711
1758
set_global_variable (classic->connection (), " super_read_only" , " ON" );
1712
1759
}
1760
+ } else {
1761
+ log_warning (" User %s already exists." , cluster_admin.c_str ());
1713
1762
}
1714
1763
}
1715
-
1716
- std::string host = instance_def->get_string (" host" );
1717
1764
int port = instance_def->get_int (" port" );
1718
- std::string endpoint = host + " :" + std::to_string (port);
1765
+ std::string endpoint = uri_host + " :" + std::to_string (port);
1719
1766
1720
1767
if (type == GRInstanceType::InnoDBCluster) {
1721
1768
auto seeds = get_peer_seeds (session->connection (), endpoint);
@@ -1725,8 +1772,16 @@ shcore::Value::Map_type_ref Dba::_check_instance_configuration(const shcore::Arg
1725
1772
1726
1773
std::string user;
1727
1774
std::string password;
1728
- user = instance_def->get_string (instance_def->has_key (" user" ) ? " user" : " dbUser" );
1729
- password = instance_def->get_string (instance_def->has_key (" password" ) ? " password" : " dbPassword" );
1775
+ // If a clusterAdmin account was specified, use it, otherwise user the
1776
+ // user of the instance.
1777
+ if (!cluster_admin.empty ()) {
1778
+ user = admin_user;
1779
+ password = cluster_admin_password;
1780
+ } else {
1781
+ user = uri_user;
1782
+ password = instance_def->get_string (
1783
+ instance_def->has_key (" password" ) ? " password" : " dbPassword" );
1784
+ }
1730
1785
1731
1786
// Get SSL values to connect to instance
1732
1787
Value::Map_type_ref instance_ssl_opts (new shcore::Value::Map_type);
@@ -1740,7 +1795,9 @@ shcore::Value::Map_type_ref Dba::_check_instance_configuration(const shcore::Arg
1740
1795
// Verbose is mandatory for checkInstanceConfiguration
1741
1796
shcore::Value::Array_type_ref mp_errors;
1742
1797
1743
- if ((_provisioning_interface->check (user, host, port, password, instance_ssl_opts, cnfpath, allow_update, mp_errors) == 0 )) {
1798
+ if ((_provisioning_interface->check (user, uri_host, port, password,
1799
+ instance_ssl_opts, cnfpath,
1800
+ allow_update, mp_errors) == 0 )) {
1744
1801
// Only return status "ok" if no previous errors were found.
1745
1802
if (errors->size () == 0 ) {
1746
1803
(*ret_val)[" status" ] = shcore::Value (" ok" );
0 commit comments