def ha_relation_joined(relation_id=None): sstpsswd = sst_password() _relation_data = { 'resources': { 'res_mysql_monitor': 'ocf:percona:mysql_monitor'}, 'resource_params': { 'res_mysql_monitor': RES_MONITOR_PARAMS % {'sstpass': sstpsswd}}, 'clones': { 'cl_mysql_monitor': 'res_mysql_monitor meta interleave=true'}, 'delete_resources': ['loc_percona_cluster', 'grp_percona_cluster', 'res_mysql_vip'] } if config('dns-ha'): update_hacluster_dns_ha('mysql', _relation_data) group_name = DNSHA_GROUP_NAME.format(service='mysql') else: update_hacluster_vip('mysql', _relation_data) group_name = VIP_GROUP_NAME.format(service='mysql') _relation_data['locations'] = { 'loc_mysql': '{} rule inf: writable eq 1'.format(group_name)} _relation_data['colocations'] = { 'colo_mysql': 'inf: {} cl_mysql_monitor'.format(group_name)} settings = { 'json_{}'.format(k): json.dumps(v, **JSON_ENCODE_OPTIONS) for k, v in _relation_data.items() if v } for rel_id in relation_ids('ha'): relation_set(relation_id=rel_id, **settings)
def ha_relation_joined(relation_id=None): sstpsswd = sst_password() _relation_data = { 'resources': { 'res_mysql_monitor': 'ocf:percona:mysql_monitor'}, 'resource_params': { 'res_mysql_monitor': RES_MONITOR_PARAMS % {'sstpass': sstpsswd}}, 'clones': { 'cl_mysql_monitor': 'res_mysql_monitor meta interleave=true'}, 'delete_resources': ['loc_percona_cluster', 'grp_percona_cluster', 'res_mysql_vip'] } if config('dns-ha'): update_hacluster_dns_ha('mysql', _relation_data) group_name = DNSHA_GROUP_NAME.format(service='mysql') else: update_hacluster_vip('mysql', _relation_data) group_name = VIP_GROUP_NAME.format(service='mysql') _relation_data['locations'] = { 'loc_mysql': '{} rule inf: writable eq 1'.format(group_name)} _relation_data['colocations'] = { 'colo_mysql': 'inf: {} cl_mysql_monitor'.format(group_name)} settings = { 'json_{}'.format(k): json.dumps(v, **JSON_ENCODE_OPTIONS) for k, v in _relation_data.items() if v } for rel_id in relation_ids('ha'): relation_set(relation_id=rel_id, **settings)
def ha_relation_joined(relation_id=None): cluster_config = get_hacluster_config() sstpsswd = sst_password() resources = {'res_mysql_monitor': 'ocf:percona:mysql_monitor'} resource_params = {'res_mysql_monitor': RES_MONITOR_PARAMS % {'sstpass': sstpsswd}} if config('dns-ha'): update_dns_ha_resource_params(relation_id=relation_id, resources=resources, resource_params=resource_params) group_name = 'grp_{}_hostnames'.format(charm_name()) groups = {group_name: 'res_{}_access_hostname'.format(charm_name())} else: vip_iface = (get_iface_for_address(cluster_config['vip']) or config('vip_iface')) vip_cidr = (get_netmask_for_address(cluster_config['vip']) or config('vip_cidr')) if config('prefer-ipv6'): res_mysql_vip = 'ocf:heartbeat:IPv6addr' vip_params = 'params ipv6addr="%s" cidr_netmask="%s" nic="%s"' % \ (cluster_config['vip'], vip_cidr, vip_iface) else: res_mysql_vip = 'ocf:heartbeat:IPaddr2' vip_params = 'params ip="%s" cidr_netmask="%s" nic="%s"' % \ (cluster_config['vip'], vip_cidr, vip_iface) resources['res_mysql_vip'] = res_mysql_vip resource_params['res_mysql_vip'] = vip_params group_name = 'grp_percona_cluster' groups = {group_name: 'res_mysql_vip'} clones = {'cl_mysql_monitor': 'res_mysql_monitor meta interleave=true'} colocations = {'colo_percona_cluster': 'inf: {} cl_mysql_monitor' ''.format(group_name)} locations = {'loc_percona_cluster': '{} rule inf: writable eq 1' ''.format(group_name)} for rel_id in relation_ids('ha'): relation_set(relation_id=rel_id, corosync_bindiface=cluster_config['ha-bindiface'], corosync_mcastport=cluster_config['ha-mcastport'], resources=resources, resource_params=resource_params, groups=groups, clones=clones, colocations=colocations, locations=locations)
def render_config(hosts=None): if hosts is None: hosts = [] config_file = resolve_cnf_file() if not os.path.exists(os.path.dirname(config_file)): os.makedirs(os.path.dirname(config_file)) context = { 'cluster_name': 'juju_cluster', 'private_address': get_cluster_host_ip(), 'cluster_hosts': ",".join(hosts), 'sst_method': config('sst-method'), 'sst_password': sst_password(), 'innodb_file_per_table': config('innodb-file-per-table'), 'table_open_cache': config('table-open-cache'), 'lp1366997_workaround': config('lp1366997-workaround'), 'binlogs_path': config('binlogs-path'), 'enable_binlogs': config('enable-binlogs'), 'binlogs_max_size': config('binlogs-max-size'), 'binlogs_expire_days': config('binlogs-expire-days'), 'performance_schema': config('performance-schema'), 'is_leader': is_leader(), 'server_id': get_server_id(), } if config('prefer-ipv6'): # NOTE(hopem): this is a kludge to get percona working with ipv6. # See lp 1380747 for more info. This is intended as a stop gap until # percona package is fixed to support ipv6. context['bind_address'] = '::' context['ipv6'] = True else: context['ipv6'] = False wsrep_provider_options = get_wsrep_provider_options() if wsrep_provider_options: context['wsrep_provider_options'] = wsrep_provider_options if CompareHostReleases(lsb_release()['DISTRIB_CODENAME']) < 'bionic': # myisam_recover is not valid for PXC 5.7 (introduced in Bionic) so we # only set it for PXC 5.6. context['myisam_recover'] = 'BACKUP' context['wsrep_provider'] = '/usr/lib/libgalera_smm.so' elif CompareHostReleases(lsb_release()['DISTRIB_CODENAME']) >= 'bionic': context['wsrep_provider'] = '/usr/lib/galera3/libgalera_smm.so' context['default_storage_engine'] = 'InnoDB' context['wsrep_log_conflicts'] = True context['innodb_autoinc_lock_mode'] = '2' context['pxc_strict_mode'] = config('pxc-strict-mode') context.update(PerconaClusterHelper().parse_config()) render(os.path.basename(config_file), config_file, context, perms=0o444)
def install_percona_xtradb_cluster(): '''Attempt PXC install based on seeding of passwords for users''' if pxc_installed(): log('MySQL already installed, skipping') return _root_password = root_password() _sst_password = sst_password() if not _root_password or not _sst_password: log('Passwords not seeded, unable to install MySQL at this' ' point so deferring installation') return configure_mysql_root_password(_root_password) apt_install(determine_packages(), fatal=True) configure_sstuser(_sst_password) if config('harden') and 'mysql' in config('harden'): run_mysql_checks()
def render_config(clustered=False, hosts=None): if hosts is None: hosts = [] config_file = resolve_cnf_file() if not os.path.exists(os.path.dirname(config_file)): os.makedirs(os.path.dirname(config_file)) context = { 'cluster_name': 'juju_cluster', 'private_address': get_cluster_host_ip(), 'clustered': clustered, 'cluster_hosts': ",".join(hosts), 'sst_method': config('sst-method'), 'sst_password': sst_password(), 'innodb_file_per_table': config('innodb-file-per-table'), 'table_open_cache': config('table-open-cache'), 'lp1366997_workaround': config('lp1366997-workaround'), 'binlogs_path': config('binlogs-path'), 'enable_binlogs': config('enable-binlogs'), 'binlogs_max_size': config('binlogs-max-size'), 'binlogs_expire_days': config('binlogs-expire-days'), 'performance_schema': config('performance-schema'), } if config('prefer-ipv6'): # NOTE(hopem): this is a kludge to get percona working with ipv6. # See lp 1380747 for more info. This is intended as a stop gap until # percona package is fixed to support ipv6. context['bind_address'] = '::' context['wsrep_provider_options'] = 'gmcast.listen_addr=tcp://:::4567;' context['ipv6'] = True else: context['ipv6'] = False context.update(PerconaClusterHelper().parse_config()) render(os.path.basename(config_file), config_file, context, perms=0o444)
def upgrade(): if is_leader(): if is_unit_paused_set(): log('Unit is paused, skiping upgrade', level=INFO) return # Leader sets on upgrade leader_set(**{'leader-ip': get_relation_ip('cluster')}) configure_sstuser(sst_password()) if not leader_get('root-password') and leader_get('mysql.passwd'): leader_set(**{'root-password': leader_get('mysql.passwd')}) # On upgrade-charm we assume the cluster was complete at some point kvstore = kv() initial_clustered = kvstore.get(INITIAL_CLUSTERED_KEY, False) if not initial_clustered: kvstore.set(key=INITIAL_CLUSTERED_KEY, value=True) kvstore.flush() # broadcast the bootstrap-uuid wsrep_ready = get_wsrep_value('wsrep_ready') or "" if wsrep_ready.lower() in ['on', 'ready']: cluster_state_uuid = get_wsrep_value('wsrep_cluster_state_uuid') if cluster_state_uuid: mark_seeded() notify_bootstrapped(cluster_uuid=cluster_state_uuid) else: # Ensure all the peers have the bootstrap-uuid attribute set # as this is all happening during the upgrade-charm hook is reasonable # to expect the cluster is running. # Wait until the leader has set the try: update_bootstrap_uuid() except LeaderNoBootstrapUUIDError: status_set('waiting', "Waiting for bootstrap-uuid set by leader")
def upgrade(): if is_leader(): if is_unit_paused_set() or is_unit_upgrading_set(): log('Unit is paused, skiping upgrade', level=INFO) return # Leader sets on upgrade leader_set(**{'leader-ip': get_relation_ip('cluster')}) configure_sstuser(sst_password()) if not leader_get('root-password') and leader_get('mysql.passwd'): leader_set(**{'root-password': leader_get('mysql.passwd')}) # On upgrade-charm we assume the cluster was complete at some point kvstore = kv() initial_clustered = kvstore.get(INITIAL_CLUSTERED_KEY, False) if not initial_clustered: kvstore.set(key=INITIAL_CLUSTERED_KEY, value=True) kvstore.flush() # broadcast the bootstrap-uuid wsrep_ready = get_wsrep_value('wsrep_ready') or "" if wsrep_ready.lower() in ['on', 'ready']: cluster_state_uuid = get_wsrep_value('wsrep_cluster_state_uuid') if cluster_state_uuid: mark_seeded() notify_bootstrapped(cluster_uuid=cluster_state_uuid) else: # Ensure all the peers have the bootstrap-uuid attribute set # as this is all happening during the upgrade-charm hook is reasonable # to expect the cluster is running. # Wait until the leader has set the try: update_bootstrap_uuid() except LeaderNoBootstrapUUIDError: status_set('waiting', "Waiting for bootstrap-uuid set by leader")
def install_percona_xtradb_cluster(): '''Attempt PXC install based on seeding of passwords for users''' if pxc_installed(): log('MySQL already installed, skipping') return if not is_leader() and not is_leader_bootstrapped(): log('Non-leader waiting on leader bootstrap, skipping percona install', DEBUG) return _root_password = root_password() _sst_password = sst_password() if not _root_password or not _sst_password: log('Passwords not seeded, unable to install MySQL at this' ' point so deferring installation') return configure_mysql_root_password(_root_password) apt_install(determine_packages(), fatal=True) configure_sstuser(_sst_password) if config('harden') and 'mysql' in config('harden'): run_mysql_checks()
def ha_relation_joined(relation_id=None): cluster_config = get_hacluster_config() sstpsswd = sst_password() resources = {'res_percona': 'ocf:heartbeat:galera'} resource_params = {} vip_iface = (get_iface_for_address(cluster_config['vip']) or config('vip_iface')) vip_cidr = (get_netmask_for_address(cluster_config['vip']) or config('vip_cidr')) if config('dns-ha'): update_dns_ha_resource_params(relation_id=relation_id, resources=resources, resource_params=resource_params) group_name = 'grp_{}_hostnames'.format(charm_name()) groups = {group_name: 'res_{}_access_hostname'.format(charm_name())} if config('prefer-ipv6'): res_mysql_vip = 'ocf:heartbeat:IPv6addr' vip_params = 'params ipv6addr="%s" cidr_netmask="%s" nic="%s"' % \ (cluster_config['vip'], vip_cidr, vip_iface) else: res_mysql_vip = 'ocf:heartbeat:IPaddr2' vip_params = 'params ip="%s" cidr_netmask="%s" nic="%s"' % \ (cluster_config['vip'], vip_cidr, vip_iface) hostname_list = get_cluster_hostnames() percona_params = \ ' params ' \ ' wsrep_cluster_address="gcomm://' + ",".join(hostname_list) + '"' \ ' config="' + resolve_cnf_file() + '"' \ ' datadir="/var/lib/percona-xtradb-cluster"' \ ' socket="/var/run/mysqld/mysqld.sock" ' \ ' pid="/var/run/mysqld/mysqld.pid"' \ ' check_user=sstuser check_passwd="' + sstpsswd + '"' \ ' binary="/usr/bin/mysqld_safe"' \ ' op monitor timeout=120 interval=20 depth=0' \ ' op monitor role=Master timeout=120 interval=10 depth=0' \ ' op monitor role=Slave timeout=120 interval=30 depth=0' percona_ms = { 'ms_percona': 'res_percona meta notify=true ' 'interleave=true master-max=3 ' 'ordered=true target-role=Started' } resource_params['res_percona'] = percona_params resources['res_mysql_vip'] = res_mysql_vip resource_params['res_mysql_vip'] = vip_params groups = {'grp_percona_cluster': 'res_mysql_vip'} colocations = { 'colo_percona_cluster': '+inf: grp_percona_cluster ms_percona:Master' } for rel_id in relation_ids('ha'): relation_set(relation_id=rel_id, corosync_bindiface=cluster_config['ha-bindiface'], corosync_mcastport=cluster_config['ha-mcastport'], resources=resources, resource_params=resource_params, ms=percona_ms, groups=groups, colocations=colocations)
def series_upgrade(): # Set this unit to series upgrading set_unit_upgrading() # The leader will "bootstrap" with no wrep peers # Non-leaders will point only at the newly upgraded leader until the # cluster series upgrade is completed. # Set cluster_series_upgrading for the duration of the cluster series # upgrade. This will be unset with the action # complete-cluster-series-upgrade on the leader node. if (leader_get('cluster_series_upgrade_leader') == get_relation_ip( 'cluster')): hosts = [] else: hosts = [leader_get('cluster_series_upgrade_leader')] # New series after series upgrade and reboot _release = lsb_release()['DISTRIB_CODENAME'].lower() if _release == "xenial": # Guarantee /var/run/mysqld exists _dir = '/var/run/mysqld' mkdir(_dir, owner="mysql", group="mysql", perms=0o755) # Install new versions of the percona packages apt_install(determine_packages()) service_stop("mysql") if _release == "bionic": render_config(hosts) if _release == "xenial": # Move the packaged version empty DB out of the way. cmd = [ "mv", "/var/lib/percona-xtradb-cluster", "/var/lib/percona-xtradb-cluster.dpkg" ] subprocess.check_call(cmd) # Symlink the previous versions data to the new cmd = ["ln", "-s", "/var/lib/mysql", "/var/lib/percona-xtradb-cluster"] subprocess.check_call(cmd) # Start mysql temporarily with no wrep for the upgrade cmd = ["mysqld"] if _release == "bionic": cmd.append("--skip-grant-tables") cmd.append("--user=mysql") cmd.append("--wsrep-provider=none") log("Starting mysqld --wsrep-provider='none' and waiting ...") proc = subprocess.Popen(cmd, stderr=subprocess.PIPE) # Wait for the mysql socket to exist check_for_socket(MYSQL_SOCKET, exists=True) # Execute the upgrade process log("Running mysql_upgrade") cmd = ['mysql_upgrade'] if _release == "xenial": cmd.append('-p{}'.format(root_password())) subprocess.check_call(cmd) # Terminate the temporary mysql proc.terminate() # Wait for the mysql socket to be removed check_for_socket(MYSQL_SOCKET, exists=False) # Clear states clear_unit_paused() clear_unit_upgrading() if _release == "xenial": # Point at the correct my.cnf cmd = [ "update-alternatives", "--set", "my.cnf", "/etc/mysql/percona-xtradb-cluster.cnf" ] subprocess.check_call(cmd) # Render config render_config(hosts) resume_unit_helper(register_configs()) # finally update the sstuser if needed. # BUG: #1838044 _sst_password = sst_password() if _sst_password: configure_sstuser(_sst_password)
def render_config(hosts=None): if hosts is None: hosts = [] config_file = resolve_cnf_file() if not os.path.exists(os.path.dirname(config_file)): os.makedirs(os.path.dirname(config_file)) context = { 'cluster_name': 'juju_cluster', 'private_address': get_cluster_host_ip(), 'cluster_hosts': ",".join(hosts), 'sst_method': config('sst-method'), 'sst_password': sst_password(), 'innodb_file_per_table': config('innodb-file-per-table'), 'table_open_cache': config('table-open-cache'), 'binlogs_path': config('binlogs-path'), 'enable_binlogs': config('enable-binlogs'), 'binlogs_max_size': config('binlogs-max-size'), 'binlogs_expire_days': config('binlogs-expire-days'), 'performance_schema': config('performance-schema'), 'is_leader': is_leader(), 'server_id': get_server_id(), 'series_upgrade': is_unit_upgrading_set(), } if config('prefer-ipv6'): # NOTE(hopem): this is a kludge to get percona working with ipv6. # See lp 1380747 for more info. This is intended as a stop gap until # percona package is fixed to support ipv6. context['bind_address'] = '::' context['ipv6'] = True else: context['ipv6'] = False wsrep_provider_options = get_wsrep_provider_options() if wsrep_provider_options: context['wsrep_provider_options'] = wsrep_provider_options if config('wsrep-slave-threads') is not None: context['wsrep_slave_threads'] = config('wsrep-slave-threads') if CompareHostReleases(lsb_release()['DISTRIB_CODENAME']) < 'bionic': # myisam_recover is not valid for PXC 5.7 (introduced in Bionic) so we # only set it for PXC 5.6. context['myisam_recover'] = 'BACKUP' context['wsrep_provider'] = '/usr/lib/libgalera_smm.so' if 'wsrep_slave_threads' not in context: context['wsrep_slave_threads'] = 1 elif CompareHostReleases(lsb_release()['DISTRIB_CODENAME']) >= 'bionic': context['wsrep_provider'] = '/usr/lib/galera3/libgalera_smm.so' context['default_storage_engine'] = 'InnoDB' context['wsrep_log_conflicts'] = True context['innodb_autoinc_lock_mode'] = '2' context['pxc_strict_mode'] = config('pxc-strict-mode') if 'wsrep_slave_threads' not in context: context['wsrep_slave_threads'] = 48 if config('databases-to-replicate'): context['databases_to_replicate'] = get_databases_to_replicate() context['server-id'] = get_server_id() context.update(PerconaClusterHelper().parse_config()) render(os.path.basename(config_file), config_file, context, perms=0o444)