Lots of refactoring

This commit is contained in:
James Page 2013-09-18 12:21:48 +01:00
parent 159217d016
commit 30b31dc3f3
6 changed files with 98 additions and 50 deletions

View File

@ -42,3 +42,9 @@ options:
type: int
default: 5490
description: Default multicast port number that will be used to communicate between HA Cluster nodes.
root-password:
type: string
description: Root password for MySQL access; must be configured pre-deployment for Active-Active clusters.
sst-password:
type: string
description: Re-sync account password for new cluster nodes; must be configured pre-deployment for Active-Active clusters.

View File

@ -1,11 +1,18 @@
''' Helper for working with a MySQL database '''
# TODO: Contribute to charm-helpers
import MySQLdb
import socket
import os
from charmhelpers.core.host import pwgen, write_file, mkdir
from charmhelpers.core.hookenv import unit_get, service_name
from charmhelpers.fetch import apt_install, filter_installed_packages
from charmhelpers.core.host import pwgen
from charmhelpers.core.hookenv import unit_get
try:
import MySQLdb
except ImportError:
apt_install(filter_installed_packages(['python-mysqldb']),
fatal=True)
import MySQLdb
class MySQLHelper():
@ -39,7 +46,6 @@ class MySQLHelper():
remote_ip))
grants = [i[0] for i in cursor.fetchall()]
except MySQLdb.OperationalError:
print "No grants found"
return False
finally:
cursor.close()
@ -69,33 +75,38 @@ class MySQLHelper():
finally:
cursor.close()
_root_passwd = '/var/lib/mysql/mysql.passwd'
_named_passwd = '/var/lib/mysql/mysql-{}.passwd'
_root_passwd = '/var/lib/charm/{}/mysql.passwd'
_named_passwd = '/var/lib/charm/{}/mysql-{}.passwd'
def get_mysql_password(username=None):
''' Retrieve or generate a mysql password for the provided username '''
def get_mysql_password(username=None, password=None):
''' Retrieve, generate or store a mysql password for
the provided username '''
if username:
_passwd_file = _named_passwd.format(username)
_passwd_file = _named_passwd.format(service_name(),
username)
else:
_passwd_file = _root_passwd
password = None
_passwd_file = _root_passwd.format(service_name())
_password = None
if os.path.exists(_passwd_file):
with open(_passwd_file, 'r') as passwd:
password = passwd.read().strip()
_password = passwd.read().strip()
else:
if not os.path.exists(os.path.dirname(_passwd_file)):
os.makedirs(os.path.dirname(_passwd_file))
password = pwgen(length=32)
with open(_passwd_file, 'w') as passwd:
passwd.write(password)
os.chmod(_passwd_file, 0600)
return password
mkdir(os.path.dirname(_passwd_file),
owner='root', group='root',
perms=0770)
# Force permissions - for some reason the chmod in makedirs fails
os.chmod(os.path.dirname(_passwd_file), 0770)
_password = password or pwgen(length=32)
write_file(_passwd_file, _password,
owner='root', group='root',
perms=0660)
return _password
def get_mysql_root_password():
def get_mysql_root_password(password=None):
''' Retrieve or generate mysql root password for service units '''
return get_mysql_password()
return get_mysql_password(username=None, password=password)
def configure_db(hostname,

View File

@ -1,8 +1,12 @@
#!/usr/bin/python
# TODO: sync passwd files from seed to peers
# TODO: Support relevant configuration options
# TODO: Add db and db-admin hooks for mysql compat
# TODO: Add README.md including squid-deb-proxy updates for repo.percona.com
# TODO: Support changes to root and sstuser passwords
import sys
import os
import glob
from charmhelpers.core.hookenv import (
Hooks, UnregisteredHookError,
log,
@ -10,7 +14,8 @@ from charmhelpers.core.hookenv import (
relation_set,
relation_ids,
unit_get,
config
config,
service_name
)
from charmhelpers.core.host import (
service_restart,
@ -31,6 +36,7 @@ from percona_utils import (
seeded, mark_seeded,
configure_mysql_root_password
)
from mysql import get_mysql_password
from charmhelpers.contrib.hahelpers.cluster import (
peer_units,
oldest_peer,
@ -39,6 +45,10 @@ from charmhelpers.contrib.hahelpers.cluster import (
is_leader
)
from mysql import configure_db
from unison import (
ssh_authorized_peers,
sync_to_peers
)
hooks = Hooks()
@ -46,11 +56,11 @@ hooks = Hooks()
@hooks.hook('install')
def install():
setup_percona_repo()
configure_mysql_root_password()
render_config() # Render base configuation no cluster
configure_mysql_root_password(config('root-password'))
render_config() # Render base configuation (no cluster)
apt_update(fatal=True)
apt_install(PACKAGES, fatal=True)
configure_sstuser()
configure_sstuser(config('sst-password'))
def render_config(clustered=False, hosts=[]):
@ -58,18 +68,32 @@ def render_config(clustered=False, hosts=[]):
os.makedirs(os.path.dirname(MY_CNF))
with open(MY_CNF, 'w') as conf:
conf.write(render_template(os.path.basename(MY_CNF),
{'cluster_name': 'juju_cluster',
'private_address': get_host_ip(),
'clustered': clustered,
'cluster_hosts': ",".join(hosts)}
)
)
{'cluster_name': 'juju_cluster',
'private_address': get_host_ip(),
'clustered': clustered,
'cluster_hosts': ",".join(hosts),
'sst_password': get_mysql_password(username='sstuser',
password=config('sst-password'))
})
)
# TODO: set 0640 and change group to mysql if avaliable
os.chmod(MY_CNF, 0644)
@hooks.hook('cluster-relation-joined')
def cluster_relation_joined():
ssh_authorized_peers(peer_interface='cluster',
user='juju_ssh', group='root',
ensure_local_user=True)
@hooks.hook('cluster-relation-changed')
@hooks.hook('upgrade-charm')
@hooks.hook('config-changed')
def cluster_changed():
ssh_authorized_peers(peer_interface='cluster',
user='juju_ssh', group='root',
ensure_local_user=True)
hosts = get_cluster_hosts()
clustered = len(hosts) > 1
pre_hash = file_hash(MY_CNF)
@ -84,6 +108,11 @@ def cluster_changed():
# Restart with new configuration
service_restart('mysql')
if eligible_leader(LEADER_RES):
files = glob.glob('/var/lib/charm/{}/*.passwd'.format(service_name()))
sync_to_peers(peer_interface='cluster',
user='juju_ssh', paths=files)
LEADER_RES = 'res_mysql_vip'
@ -149,6 +178,10 @@ def shared_db_changed():
relation_set(**return_data)
relation_set(db_host=db_host)
files = glob.glob('/var/lib/charm/{}/*.passwd'.format(service_name()))
sync_to_peers(peer_interface='cluster',
user='juju_ssh', paths=files)
@hooks.hook('ha-relation-joined')
def ha_relation_joined():
@ -162,18 +195,12 @@ def ha_relation_joined():
log('Insufficient VIP information to configure cluster')
sys.exit(1)
resources = {
'res_mysql_vip': 'ocf:heartbeat:IPaddr2',
}
resources = {'res_mysql_vip': 'ocf:heartbeat:IPaddr2'}
resource_params = {
'res_mysql_vip': 'params ip="%s" cidr_netmask="%s" nic="%s"' % \
(vip, vip_cidr, vip_iface),
}
groups = {
'grp_percona_cluster': 'res_mysql_vip',
}
groups = {'grp_percona_cluster': 'res_mysql_vip'}
for rel_id in relation_ids('ha'):
relation_set(rid=rel_id,

View File

@ -14,7 +14,7 @@ from charmhelpers.core.hookenv import (
)
from charmhelpers.fetch import (
apt_install,
filter_installed_packages
filter_installed_packages,
)
from mysql import get_mysql_root_password
@ -35,7 +35,7 @@ except ImportError:
PACKAGES = [
'percona-xtradb-cluster-server-5.5',
'percona-xtradb-cluster-client-5.5',
'python-mysqldb'
'unison'
]
KEY = "keys/repo.percona.com"
@ -72,6 +72,7 @@ def render_template(template_name, context, template_dir=TEMPLATES_DIR):
return template.render(context)
# TODO: goto charm-helpers (I use this everywhere)
def get_host_ip(hostname=None):
hostname = hostname or unit_get('private-address')
try:
@ -94,23 +95,26 @@ def get_cluster_hosts():
unit, relid)))
return hosts
# TODO: refactor to use mysql helper when it support setting arbitary
# permissions
SQL_SST_USER_SETUP = """mysql --user=root --password={} << EOF
CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 's3cretPass';
CREATE USER 'sstuser'@'localhost' IDENTIFIED BY '{}';
GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';
EOF"""
def configure_sstuser():
subprocess.check_call(SQL_SST_USER_SETUP.format(get_mysql_root_password()),
def configure_sstuser(sst_password):
subprocess.check_call(SQL_SST_USER_SETUP.format(get_mysql_root_password(),
sst_password),
shell=True)
# TODO: mysql charmhelper
def configure_mysql_root_password():
def configure_mysql_root_password(password):
''' Configure debconf with root password '''
dconf = Popen(['debconf-set-selections'], stdin=PIPE)
package = "percona-server-server"
root_pass = get_mysql_root_password()
root_pass = get_mysql_root_password(password)
dconf.stdin.write("%s %s/root_password password %s\n" %
(package, package, root_pass))
dconf.stdin.write("%s %s/root_password_again password %s\n" %

View File

@ -1 +1 @@
23
31

View File

@ -34,6 +34,6 @@ wsrep_sst_method=xtrabackup
wsrep_cluster_name={{ cluster_name }}
# Authentication for SST method
wsrep_sst_auth="sstuser:s3cretPass"
wsrep_sst_auth="sstuser:{{ sst_password }}"
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/conf.d/