Skip to content

Commit

Permalink
mysql: manager connects to the db using the root account
Browse files Browse the repository at this point in the history
This commit changes the behavior of the manager to make it use the root account (instead of the user's account) when connecting to the mysql database. This fixes a bug in which the two passwords become desynchronized and access is denied. So, now, the manager and agents only use the root password to connect the database and only store the root password, not the user's password. Access for the root account from the manager IP address is granted.

The commit also renames the IP_WHITE_LIST parameter in the agent configuration with MANAGER_IP, to better reflect its content.

Some logging messages are also improved and the root password is removed from the logs.
  • Loading branch information
tcrivat committed Jul 17, 2016
1 parent 6356848 commit 565e9f7
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 37 deletions.
4 changes: 1 addition & 3 deletions conpaas-director/cpsdirector/iaas/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,9 @@ def _set_clouds(self):
#=========================================================================#
# generate_context(self, service_name, replace, cloud) #
#=========================================================================#
def generate_context(self, clouds, context_replacement={}, startup_script=None, ip_whitelist=None):
def generate_context(self, clouds, context_replacement={}, startup_script=None):
"""Generates the contextualization file for the given clouds.
"""
# COMMENT (genc): what is ip_whitelist?

for cloud_name in clouds:
cloud = self.get_cloud_by_name(cloud_name)

Expand Down
3 changes: 1 addition & 2 deletions conpaas-services/config/agent/default-agent.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ VAR_CACHE = $VAR_CACHE
VAR_RUN = $VAR_RUN
CONPAAS_HOME = $CPS_HOME

# Will be filled in by the manager
IP_WHITE_LIST = $MANAGER_IP
MANAGER_IP = $MANAGER_IP

IPOP_BASE_NAMESPACE = $IPOP_BASE_NAMESPACE

Expand Down
2 changes: 1 addition & 1 deletion conpaas-services/scripts/agent/htc-agent-start
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ grep CLOUD_MAX_VMS_ALL_CLOUDS $ROOT_DIR/config.cfg | sed 's/CLOUD_MAX_VMS_ALL_CL
grep CLOUD_MAX_VMS.= $ROOT_DIR/config.cfg | sed 's/CLOUD_MAX_VMS = \(.*\)/CloudMaxVms = \1/' >> /etc/condor/condor_config.local
echo 'STARTD_ATTRS = $(STARTD_ATTRS) CloudName CloudType CloudMachineType CloudCostPerTime CloudMaxVms CloudMaxVmsAllClouds' >> /etc/condor/condor_config.local

grep IP_WHITE_LIST $ROOT_DIR/config.cfg | sed 's/.*= //;s/$/ master.htc/' >> /etc/hosts
grep MANAGER_IP $ROOT_DIR/config.cfg | sed 's/.*= //;s/$/ master.htc/' >> /etc/hosts
# TODO: run everything as user condor, for now make the execute directory writable for world
chmod 777 /var/lib/condor/execute
condor_restart
Expand Down
2 changes: 1 addition & 1 deletion conpaas-services/scripts/agent/htcondor-agent-start
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ CONDOR_HOST = master.htc
ALLOW_WRITE = *.htc
" >> /etc/condor/condor_config.local

grep IP_WHITE_LIST $ROOT_DIR/config.cfg | sed 's/.*= //;s/$/ master.htc/' >> /etc/hosts
grep MANAGER_IP $ROOT_DIR/config.cfg | sed 's/.*= //;s/$/ master.htc/' >> /etc/hosts
# TODO: run everything as user condor, for now make the execute directory writable for world
chmod 777 /var/lib/condor/execute
condor_restart
Expand Down
2 changes: 1 addition & 1 deletion conpaas-services/src/conpaas/core/ganglia.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,5 @@ def __init__(self, config_parser):
"""Same as for the base case, but with proper manager_ip"""
BaseGanglia.__init__(self)

self.manager_ip = config_parser.get('agent', 'IP_WHITE_LIST')
self.manager_ip = config_parser.get('agent', 'MANAGER_IP')
self.cps_home = config_parser.get('agent', 'CONPAAS_HOME')
2 changes: 1 addition & 1 deletion conpaas-services/src/conpaas/services/mysql/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ VAR_RUN =
CONPAAS_HOME = /home/miha/projects/conpaas

# Will be filled in by the manager
IP_WHITE_LIST =
MANAGER_IP =

IPOP_BASE_NAMESPACE = $IPOP_BASE_NAMESPACE

Expand Down
39 changes: 24 additions & 15 deletions conpaas-services/src/conpaas/services/mysql/agent/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(self, config, nodes, device_name):
self.mkdir_cmd = "mkdir -p %s" % self.mount_point
self.mount(True)
except ConfigParser.Error:
sql_logger.exception('Could not mount the device')
sql_logger.warning('Could not mount the device')
sql_logger.debug("Entering init MySQLServerConfiguration")
try:
#hostname = socket.gethostname()
Expand All @@ -59,10 +59,11 @@ def __init__(self, config, nodes, device_name):
sql_logger.debug("Trying to get params from configuration file ")
self.conn_location = config.get('MySQL_root_connection', 'location')
self.conn_username = config.get("MySQL_root_connection", "username")
self.conn_password = config.get("MySQL_root_connection", "password")
self.conn_password = config.get("MySQL_root_connection", "password") # root password
sql_logger.debug("Got parameters for root connection to MySQL")

# Get MySQL configuration parameters
self.manager_ip = config.get('agent', 'MANAGER_IP')
self.mysqldump_path = config.get('agent', 'MYSQLDUMP_PATH')
self.mycnf_filepath = config.get("MySQL_configuration", "my_cnf_file")
self.path_mysql_ssr = config.get("MySQL_configuration", "path_mysql_ssr")
Expand Down Expand Up @@ -125,14 +126,14 @@ def __init__(self, config, nodes, device_name):
# Change root password when starting
if is_first_node:
os.system("mysqladmin -u root password " + self.conn_password)
#TODO: add user conn_userame and grant privileges to it from any host
self.allow_root_connections(self.manager_ip)
self.add_user(self.conn_username, self.conn_password)
self.add_user(self.wsrep_user, self.wsrep_password)

except ConfigParser.Error:
sql_logger.exception('Could not read config file')
sql_logger.warning('Could not read config file')
except IOError:
sql_logger.exception('Config file doesn\'t exist')
sql_logger.warning('Config file doesn\'t exist')

# Creating a supervisor object
sql_logger.debug("Leaving init MySQLServerConfiguration")
Expand All @@ -148,7 +149,7 @@ def _load_dump(self, f):
#os.system('rm /tmp/mysqldump.db')
sql_logger.debug("Leaving load_dump")
except Exception as e:
sql_logger.exception('Failed to load dump')
sql_logger.warning('Failed to load dump')
raise e

def _wait_daemon_started(self, is_first_node):
Expand All @@ -164,7 +165,7 @@ def _wait_daemon_started(self, is_first_node):
"-BN "
"-e \"SHOW STATUS LIKE 'wsrep_local_state_comment';\""
% password)
sql_logger.debug("Polling mysql daemon: %s" % poll_cmd)
sql_logger.debug("Polling the MySQL daemon") #: %s" % poll_cmd)
out, error, code = run_cmd_code(poll_cmd)
if code != 0:
wait_time = 5
Expand All @@ -191,7 +192,7 @@ def start(self, is_first_node):
return_code = proc.wait()
if return_code != 0:
self.state = S_STOPPED
raise Exception('Failed to start MySQL Galera daemon: return code is %s.' % return_code)
raise Exception('Failed to start MySQL daemon: return code is %s.' % return_code)
sql_logger.info('MySQL server started, checking if it\'s ready')
self._wait_daemon_started(is_first_node)
self.state = S_RUNNING
Expand All @@ -208,12 +209,12 @@ def stop(self):
self.state = S_STOPPED
sql_logger.info('Daemon mysqld stopped')
except Exception as e:
sql_logger.exception('Failed to stop MySQL daemon: %s' % e)
sql_logger.warning('Failed to stop MySQL daemon: %s' % e)
raise e
try:
self.unmount()
except Exception as e:
sql_logger.exception('Failed to unmount disk %s' % self.dev_name)
sql_logger.warning('Failed to unmount disk %s' % self.dev_name)
raise e
else:
sql_logger.warning('Requested to stop MySQL daemon'
Expand Down Expand Up @@ -285,6 +286,14 @@ def take_snapshot(self):
db1.close()
return ret

def allow_root_connections(self, manager_ip):
db = MySQLdb.connect(self.conn_location, 'root', self.conn_password)
exc = db.cursor()
exc.execute("create user 'root'@'" + manager_ip + "' identified by '" + self.conn_password + "'")
exc.execute("grant all privileges on *.* TO 'root'@'" + manager_ip + "' with grant option;")
exc.execute("flush privileges;")
db.close()

def add_user(self, new_username, new_password):
db = MySQLdb.connect(self.conn_location, 'root', self.conn_password)
exc = db.cursor()
Expand Down Expand Up @@ -341,7 +350,7 @@ def mount(self, mkfs):
dev_prefix = self.dev_name.split('/')[2][:-1]

for attempt in range(1, 11):
sql_logger.info("Galera node waiting for block device %s" % self.dev_name)
sql_logger.info("MySQL node waiting for block device %s" % self.dev_name)
if lexists(self.dev_name):
dev_found = True
break
Expand All @@ -359,7 +368,7 @@ def mount(self, mkfs):
run_cmd(self.mkdir_cmd)

if dev_found:
sql_logger.info("Galera node has now access to %s" % self.dev_name)
sql_logger.info("MySQL node has now access to %s" % self.dev_name)

# prepare block device
if mkfs:
Expand Down Expand Up @@ -395,22 +404,22 @@ def mount(self, mkfs):

def unmount(self):
# kill all processes still using the volume
sql_logger.info("Killing all processes using the Galera Disk")
sql_logger.info("Killing all processes using the storage volume")
fuser_args = ['fuser', '-km', self.dev_name]
fuser_cmd = ' '.join(fuser_args)
sql_logger.debug("Running command '%s'" % fuser_cmd)
run_cmd(fuser_cmd)

# unmount
sql_logger.info("Trying to unmount the Galera Disk")
sql_logger.info("Trying to unmount the storage volume")
unmount_args = ['umount', self.dev_name]
unmount_cmd = ' '.join(unmount_args)
sql_logger.debug("Running command '%s'" % unmount_cmd)
_, err = run_cmd(unmount_cmd)
if err:
sql_logger.critical('Failed to unmount storage device: %s' % err)
else:
sql_logger.info("Galera node has succesfully unmounted %s" % self.dev_name)
sql_logger.info("MySQL node has succesfully unmounted %s" % self.dev_name)


class GLBNode(object):
Expand Down
23 changes: 11 additions & 12 deletions conpaas-services/src/conpaas/services/mysql/manager/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ def _start_mysqld(self, nodes):
raise
try:
glb_nodes = self.config.get_glb_nodes()
self.logger.debug('MySQL Galera node already active: %s' % glb_nodes)
self.logger.debug('MySQL nodes already active: %s' % glb_nodes)
nodesIp=[]
nodesIp = ["%s:%s" % (node.ip, self.config.MYSQL_PORT) # FIXME: find real mysql port instead of default 3306
for node in nodes]
for glb in glb_nodes:
agent.add_glbd_nodes(glb.ip, self.config.AGENT_PORT, nodesIp)
return True
except Exception as ex:
self.logger.exception('Failed to configure new MySQL GLB: %s' % ex)
self.logger.exception('Failed to configure new GLB node: %s' % ex)
raise

def _start_glbd(self, new_glb_nodes):
Expand All @@ -111,7 +111,7 @@ def _start_glbd(self, new_glb_nodes):
self.logger.debug('create_glb_node for new_glb.ip = %s' % new_glb.ip)
agent.start_glbd(new_glb.ip, self.config.AGENT_PORT, nodes)
except AgentException:
self.logger.exception('Failed to start MySQL GLB Node at node %s' % new_glb.ip)
self.logger.exception('Failed to start GLB at node %s' % new_glb.ip)
raise

@expose('GET')
Expand Down Expand Up @@ -230,8 +230,8 @@ def getMeanLoad(self, kwargs):
inserts=[]
insert=0
for node in nodes:
# self.logger.debug('connecting to: %s, using username: %s and pwd: %s' % (node.ip, 'mysqldb', self.root_pass))
db = MySQLdb.connect(node.ip, 'mysqldb', self.root_pass)
# self.logger.debug('connecting to: %s, using username: %s and pwd: %s' % (node.ip, 'root', self.root_pass))
db = MySQLdb.connect(node.ip, 'root', self.root_pass)
exc = db.cursor()
exc.execute("SHOW STATUS LIKE 'wsrep_local_recv_queue_avg';")
localLoad=exc.fetchone()[1]
Expand Down Expand Up @@ -441,7 +441,7 @@ def _do_migrate_nodes(self, migration_plan, delay):
new_nodes = []
# TODO: make it parallel
for cloud, count in new_vm_nb.iteritems():
self.controller.add_context_replacement(dict(mysql_username='mysqldb',
self.controller.add_context_replacement(dict(mysql_username='root',
mysql_password=self.root_pass),
cloud=cloud)

Expand Down Expand Up @@ -526,13 +526,12 @@ def set_password(self, kwargs):
user, password = check_arguments(exp_params, kwargs)
self.check_state([self.S_RUNNING])
except Exception as ex:
return HttpErrorResponse("Cannot set new password: %s." % ex)
return HttpErrorResponse("%s" % ex)

one_node = self.config.get_nodes()[0]

try:
agent.set_password(one_node.ip, self.config.AGENT_PORT, user, password)
self.root_pass = password
except Exception as ex:
self.logger.exception()
return HttpErrorResponse('Failed to set new password: %s.' % ex)
Expand Down Expand Up @@ -596,10 +595,10 @@ def sqldump(self, kwargs):
one_node = self.config.get_nodes()[0]
# adding option '--skip-lock-tables' to avoid issue
# mysqldump: Got error: 1142: SELECT,LOCK TABL command denied to user
# 'mysqldb'@'10.158.0.28' for table 'cond_instances'
# 'root'@'10.158.0.28' for table 'cond_instances'
# when using LOCK TABLES
# FIXME: is it MySQL 5.1 only? does it still occur with MySQL 5.5?
cmd = 'mysqldump -u mysqldb -h %s --password=%s -A --skip-lock-tables' \
cmd = 'mysqldump -u root -h %s --password=%s -A --skip-lock-tables' \
% (one_node.ip, self.root_pass)
out, error, return_code = run_cmd_code(cmd)

Expand Down Expand Up @@ -673,13 +672,13 @@ def setMySqlParams(self, kwargs):
self.check_state([self.S_RUNNING])
nodes = self.config.get_nodes()
for node in nodes:
db = MySQLdb.connect(node.ip, 'mysqldb', self.root_pass)
db = MySQLdb.connect(node.ip, 'root', self.root_pass)
exc = db.cursor()
exc.execute('set global ' + variable + ' = ' + value + ';')
'''glb_nodes = self.config.get_glb_nodes()
n=len(nodes)*value
for node in glb_nodes:
db = MySQLdb.connect(node.ip, 'mysqldb', self.root_pass,port=8010)
db = MySQLdb.connect(node.ip, 'root', self.root_pass,port=8010)
exc = db.cursor()
exc.execute('set global ' + variable + ' = ' + n + ';')'''
except Exception as ex:
Expand Down
2 changes: 1 addition & 1 deletion conpaas-services/src/tests/core/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def config_parser():
config_parser.set('agent', 'TYPE', 'test')
config_parser.set('agent', 'USER_ID', '1')
config_parser.set('agent', 'SERVICE_ID', '1')
config_parser.set('agent', 'IP_WHITE_LIST', '127.0.0.1')
config_parser.set('agent', 'MANAGER_IP', '127.0.0.1')
config_parser.set('agent', 'CONPAAS_HOME', '/dev/null')
return config_parser

Expand Down

0 comments on commit 565e9f7

Please sign in to comment.