def assess_status_helper(): """Assess status of unit @returns status, message - status is workload status and message is any corresponding messages """ if config('stonith_enabled') in ['true', 'True', True]: return ('blocked', 'stonith_enabled config option is no longer supported') if is_unit_upgrading_set(): return ("blocked", "Ready for do-release-upgrade. Set complete when finished") if is_waiting_unit_series_upgrade_set(): return ("blocked", "HA services shutdown, peers are ready for series upgrade") if is_unit_paused_set(): return ("maintenance", "Paused. Use 'resume' action to resume normal service.") node_count = int(config('cluster_count')) status = 'active' message = 'Unit is ready and clustered' try: try_pcmk_wait() except pcmk.ServicesNotUp: message = 'Pacemaker is down' status = 'blocked' for relid in relation_ids('hanode'): if len(related_units(relid)) + 1 < node_count: status = 'blocked' message = ("Insufficient peer units for ha cluster " "(require {})".format(node_count)) # if the status was not changed earlier, we verify the maintenance status try: if status == 'active': prop = pcmk.get_property('maintenance-mode').strip() except pcmk.PropertyNotFound: # the property is not the output of 'crm configure show xml', so we use # the default value for this property. For crmsh>=2.2.0 the default # value is automatically provided by show-property or get-property. prop = 'false' if (status == 'active' and prop == 'true'): # maintenance mode enabled in pacemaker status = 'maintenance' message = 'Pacemaker in maintenance mode' for resource in get_resources().keys(): if not pcmk.is_resource_present(resource): return ("waiting", "Resource: {} not yet configured".format(resource)) if not pcmk.crm_res_running_on_node(resource, get_hostname()): return ("blocked", "Resource: {} not running".format(resource)) return status, message
def configure_legacy_stonith(): if config('stonith_enabled') not in ['true', 'True', True]: if configure_pacemaker_remote_stonith_resource(): log('Not disabling STONITH as pacemaker remotes are present', level=INFO) else: log('Disabling STONITH', level=INFO) cmd = "crm configure property stonith-enabled=false" pcmk.commit(cmd) else: log('Enabling STONITH for all nodes in cluster.', level=INFO) # configure stontih resources for all nodes in cluster. # note: this is totally provider dependent and requires # access to the MAAS API endpoint, using endpoint and credentials # set in config. url = config('maas_url') creds = config('maas_credentials') if None in [url, creds]: msg = 'maas_url and maas_credentials must be set ' \ 'in config to enable STONITH.' status_set('blocked', msg) raise Exception(msg) nodes = maas.MAASHelper(url, creds).list_nodes() if not nodes: msg = 'Could not obtain node inventory from ' \ 'MAAS @ %s.' % url status_set('blocked', msg) raise Exception(msg) cluster_nodes = pcmk.list_nodes() for node in cluster_nodes: rsc, constraint = pcmk.maas_stonith_primitive(nodes, node) if not rsc: msg = 'Failed to determine STONITH primitive for ' \ 'node %s' % node status_set('blocked', msg) raise Exception(msg) rsc_name = str(rsc).split(' ')[1] if not pcmk.is_resource_present(rsc_name): log('Creating new STONITH primitive %s.' % rsc_name, level=DEBUG) cmd = 'crm -F configure %s' % rsc pcmk.commit(cmd) if constraint: cmd = 'crm -F configure %s' % constraint pcmk.commit(cmd) else: log('STONITH primitive already exists for node.', level=DEBUG) pcmk.commit("crm configure property stonith-enabled=true")
def configure_stonith(): if config('stonith_enabled') not in ['true', 'True', True]: if configure_pacemaker_remote_stonith_resource(): log('Not disabling STONITH as pacemaker remotes are present', level=INFO) else: log('Disabling STONITH', level=INFO) cmd = "crm configure property stonith-enabled=false" pcmk.commit(cmd) else: log('Enabling STONITH for all nodes in cluster.', level=INFO) # configure stontih resources for all nodes in cluster. # note: this is totally provider dependent and requires # access to the MAAS API endpoint, using endpoint and credentials # set in config. url = config('maas_url') creds = config('maas_credentials') if None in [url, creds]: msg = 'maas_url and maas_credentials must be set ' \ 'in config to enable STONITH.' status_set('blocked', msg) raise Exception(msg) nodes = maas.MAASHelper(url, creds).list_nodes() if not nodes: msg = 'Could not obtain node inventory from ' \ 'MAAS @ %s.' % url status_set('blocked', msg) raise Exception(msg) cluster_nodes = pcmk.list_nodes() for node in cluster_nodes: rsc, constraint = pcmk.maas_stonith_primitive(nodes, node) if not rsc: msg = 'Failed to determine STONITH primitive for ' \ 'node %s' % node status_set('blocked', msg) raise Exception(msg) rsc_name = str(rsc).split(' ')[1] if not pcmk.is_resource_present(rsc_name): log('Creating new STONITH primitive %s.' % rsc_name, level=DEBUG) cmd = 'crm -F configure %s' % rsc pcmk.commit(cmd) if constraint: cmd = 'crm -F configure %s' % constraint pcmk.commit(cmd) else: log('STONITH primitive already exists for node.', level=DEBUG) pcmk.commit("crm configure property stonith-enabled=true")
def configure_pacemaker_remote(remote_hostname, remote_ip): """Create a resource corresponding to the pacemaker remote node. :param remote_hostname: Remote hostname used for registering remote node. :type remote_hostname: str :param remote_ip: Remote IP used for registering remote node. :type remote_ip: str :returns: Name of resource for pacemaker remote node. :rtype: str """ resource_name = remote_hostname if not pcmk.is_resource_present(resource_name): cmd = ("crm configure primitive {} ocf:pacemaker:remote " "params server={} reconnect_interval=60 " "op monitor interval=30s").format(resource_name, remote_ip) pcmk.commit(cmd, failure_is_fatal=True) return resource_name
def configure_maas_stonith_resource(stonith_hostnames): """Create stonith resource for the given hostname. :param stonith_hostnames: The hostnames that the stonith management system refers to the remote node as. :type stonith_hostname: List """ hostnames = [] for host in stonith_hostnames: hostnames.append(host) if '.' in host: hostnames.append(host.split('.')[0]) hostnames = list(set(hostnames)) ctxt = { 'url': config('maas_url'), 'apikey': config('maas_credentials'), 'hostnames': ' '.join(sorted(hostnames))} if all(ctxt.values()): maas_login_params = "url='{url}' apikey='{apikey}'".format(**ctxt) maas_rsc_hash = pcmk.resource_checksum( 'st', 'stonith:external/maas', res_params=maas_login_params)[:7] ctxt['stonith_resource_name'] = 'st-maas-{}'.format(maas_rsc_hash) ctxt['resource_params'] = ( "params url='{url}' apikey='{apikey}' hostnames='{hostnames}' " "op monitor interval=25 start-delay=25 " "timeout=25").format(**ctxt) if pcmk.is_resource_present(ctxt['stonith_resource_name']): pcmk.crm_update_resource( ctxt['stonith_resource_name'], 'stonith:external/maas', ctxt['resource_params']) else: cmd = ( "crm configure primitive {stonith_resource_name} " "stonith:external/maas {resource_params}").format(**ctxt) pcmk.commit(cmd, failure_is_fatal=True) pcmk.commit( "crm configure property stonith-enabled=true", failure_is_fatal=True) else: raise ValueError("Missing configuration: {}".format(ctxt)) return {ctxt['stonith_resource_name']: 'stonith:external/maas'}
def _configure_stonith_resource(ctxt): hostnames = [] for host in ctxt['stonith_hostnames']: hostnames.append(host) if '.' in host: hostnames.append(host.split('.')[0]) ctxt['hostnames'] = ' '.join(sorted(list(set(hostnames)))) if all(ctxt.values()): ctxt['resource_params'] = ctxt['resource_params'].format(**ctxt) if pcmk.is_resource_present(ctxt['stonith_resource_name']): pcmk.crm_update_resource(ctxt['stonith_resource_name'], ctxt['stonith_plugin'], ctxt['resource_params']) else: cmd = ("crm configure primitive {stonith_resource_name} " "{stonith_plugin} {resource_params}").format(**ctxt) pcmk.commit(cmd, failure_is_fatal=True) else: raise ValueError("Missing configuration: {}".format(ctxt))
def configure_pacemaker_remote(remote_hostname, remote_ip): """Create a resource corresponding to the pacemaker remote node. :param remote_hostname: Remote hostname used for registering remote node. :type remote_hostname: str :param remote_ip: Remote IP used for registering remote node. :type remote_ip: str :returns: Name of resource for pacemaker remote node. :rtype: str """ resource_name = remote_hostname.split('.')[0] if not pcmk.is_resource_present(resource_name): cmd = ( "crm configure primitive {} ocf:pacemaker:remote " "params server={} reconnect_interval=60 " "op monitor interval=30s").format(resource_name, remote_ip) pcmk.commit(cmd, failure_is_fatal=True) return resource_name