def prometheus_relation(relid=None, unit=None, prometheus_permitted=None, module_enabled=None): if not ceph.is_bootstrapped(): return if prometheus_permitted is None: prometheus_permitted = cmp_pkgrevno('ceph', '12.2.0') >= 0 if module_enabled is None: module_enabled = (is_mgr_module_enabled('prometheus') or mgr_enable_module('prometheus')) log("checking if prometheus module is enabled") if prometheus_permitted and module_enabled: log("Updating prometheus") data = { 'hostname': get_relation_ip('prometheus'), 'port': 9283, } relation_set(relation_id=relid, relation_settings=data) else: log("Couldn't enable prometheus, but are related. " "Prometheus is available in Ceph version: {} ; " "Prometheus Module is enabled: {}".format(prometheus_permitted, module_enabled), level=WARNING)
def notify_prometheus(): if relation_ids('prometheus') and ceph.is_bootstrapped(): prometheus_permitted = cmp_pkgrevno('ceph', '12.2.0') >= 0 module_enabled = (is_mgr_module_enabled('prometheus') or mgr_enable_module('prometheus')) for relid in relation_ids('prometheus'): for unit in related_units(relid): prometheus_relation(relid=relid, unit=unit, prometheus_permitted=prometheus_permitted, module_enabled=module_enabled)
def check_for_upgrade(): if not ceph.is_bootstrapped(): log("Ceph is not bootstrapped, skipping upgrade checks.") return c = hookenv.config() old_version = ceph.resolve_ceph_version(c.previous('source') or 'distro') log('old_version: {}'.format(old_version)) # Strip all whitespace new_version = ceph.resolve_ceph_version(hookenv.config('source')) old_version_os = get_os_codename_install_source( c.previous('source') or 'distro') new_version_os = get_os_codename_install_source(hookenv.config('source')) log('new_version: {}'.format(new_version)) if (old_version in ceph.UPGRADE_PATHS and new_version == ceph.UPGRADE_PATHS[old_version]): log("{} to {} is a valid upgrade path. Proceeding.".format( old_version, new_version)) ceph.roll_monitor_cluster(new_version=new_version, upgrade_key='admin') elif (old_version == new_version and old_version_os < new_version_os): # See LP: #1778823 add_source(hookenv.config('source'), hookenv.config('key')) log(("The installation source has changed yet there is no new major " "version of Ceph in this new source. As a result no package " "upgrade will take effect. Please upgrade manually if you need " "to."), level=INFO) else: # Log a helpful error message log("Invalid upgrade path from {} to {}. " "Valid paths are: {}".format(old_version, new_version, ceph.pretty_print_upgrade_paths()), level=ERROR)
def mon_relation(): if leader_get('monitor-secret') is None: log('still waiting for leader to setup keys') status_set('waiting', 'Waiting for leader to setup keys') return emit_cephconf() moncount = int(config('monitor-count')) if len(get_mon_hosts()) >= moncount: if ceph.is_bootstrapped(): # The ceph-mon unit chosen for handling broker requests is based on # internal Ceph MON leadership and not Juju leadership. To update # the rbd-mirror relation on all ceph-mon units after pool creation # the unit handling the broker request will update a nonce on the # mon relation. notify_rbd_mirrors() else: status_set('maintenance', 'Bootstrapping MON cluster') # the following call raises an exception # if it can't add the keyring try: ceph.bootstrap_monitor_cluster(leader_get('monitor-secret')) except FileNotFoundError as e: # NOQA -- PEP8 is still PY2 log("Couldn't bootstrap the monitor yet: {}".format(str(e))) exit(0) ceph.wait_for_bootstrap() ceph.wait_for_quorum() ceph.create_keyrings() if cmp_pkgrevno('ceph', '12.0.0') >= 0: status_set('maintenance', 'Bootstrapping Ceph MGR') ceph.bootstrap_manager() if ceph.monitor_key_exists('admin', 'autotune'): autotune = ceph.monitor_key_get('admin', 'autotune') else: ceph.wait_for_manager() autotune = config('pg-autotune') if (cmp_pkgrevno('ceph', '14.2.0') >= 0 and (autotune == 'true' or autotune == 'auto')): ceph.monitor_key_set('admin', 'autotune', 'true') else: ceph.monitor_key_set('admin', 'autotune', 'false') if ceph.monitor_key_get('admin', 'autotune') == 'true': try: mgr_enable_module('pg_autoscaler') except subprocess.CalledProcessError: log( "Failed to initialize autoscaler, it must be " "initialized on the last monitor", level='info') # If we can and want to if is_leader() and config('customize-failure-domain'): # But only if the environment supports it if os.environ.get('JUJU_AVAILABILITY_ZONE'): cmds = [ "ceph osd getcrushmap -o /tmp/crush.map", "crushtool -d /tmp/crush.map| " "sed 's/step chooseleaf firstn 0 type host/step " "chooseleaf firstn 0 type rack/' > " "/tmp/crush.decompiled", "crushtool -c /tmp/crush.decompiled -o /tmp/crush.map", "crushtool -i /tmp/crush.map --test", "ceph osd setcrushmap -i /tmp/crush.map" ] for cmd in cmds: try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError as e: log("Failed to modify crush map:", level='error') log("Cmd: {}".format(cmd), level='error') log("Error: {}".format(e.output), level='error') break else: log("Your Juju environment doesn't" "have support for Availability Zones") notify_osds() notify_radosgws() notify_client() notify_rbd_mirrors() notify_prometheus() else: log('Not enough mons ({}), punting.'.format(len(get_mon_hosts())))
def config_changed(): # Get the cfg object so we can see if the no-bootstrap value has changed # and triggered this hook invocation cfg = config() if config('prefer-ipv6'): assert_charm_supports_ipv6() check_for_upgrade() log('Monitor hosts are ' + repr(get_mon_hosts())) sysctl_dict = config('sysctl') if sysctl_dict: create_sysctl(sysctl_dict, '/etc/sysctl.d/50-ceph-charm.conf') if relations_of_type('nrpe-external-master'): update_nrpe_config() if config('enable-dashboard') and cmp_pkgrevno('ceph', '14.2.0') >= 0: apt_install(packages=filter_installed_packages(['ceph-mgr-dashboard'])) if is_leader(): if not config('no-bootstrap'): if not leader_get('fsid') or not leader_get('monitor-secret'): if config('fsid'): fsid = config('fsid') else: fsid = "{}".format(uuid.uuid1()) if config('monitor-secret'): mon_secret = config('monitor-secret') else: mon_secret = "{}".format(ceph.generate_monitor_secret()) opts = { 'fsid': fsid, 'monitor-secret': mon_secret, } try: leader_set(opts) status_set('maintenance', 'Created FSID and Monitor Secret') log("Settings for the cluster are: {}".format(opts)) except Exception as e: # we're probably not the leader an exception occured # let's log it anyway. log("leader_set failed: {}".format(str(e))) elif (cfg.changed('no-bootstrap') and is_relation_made('bootstrap-source')): # User changed the no-bootstrap config option, we're the leader, # and the bootstrap-source relation has been made. The charm should # be in a blocked state indicating that the no-bootstrap option # must be set. This block is invoked when the user is trying to # get out of that scenario by enabling no-bootstrap. bootstrap_source_relation_changed() # This will only ensure that we are enabled if the 'pg-autotune' option # is explicitly set to 'true', and not if it is 'auto' or 'false' if (config('pg-autotune') == 'true' and cmp_pkgrevno('ceph', '14.2.0') >= 0): # The return value of the enable_module call will tell us if the # module was already enabled, in which case, we don't need to # re-configure the already configured pools if mgr_enable_module('pg_autoscaler'): ceph.monitor_key_set('admin', 'autotune', 'true') for pool in ceph.list_pools(): enable_pg_autoscale('admin', pool) if (config('enable-dashboard') and cmp_pkgrevno('ceph', '14.2.0') >= 0): log("enable-dashboard: {}".format(str(config('enable-dashboard')))) if mgr_enable_module('dashboard'): pass log("configure-dashboard") configure_dashboard() # unconditionally verify that the fsid and monitor-secret are set now # otherwise we exit until a leader does this. if leader_get('fsid') is None or leader_get('monitor-secret') is None: log('still waiting for leader to setup keys') status_set('waiting', 'Waiting for leader to setup keys') return emit_cephconf() # Support use of single node ceph if (not ceph.is_bootstrapped() and int(config('monitor-count')) == 1 and is_leader()): status_set('maintenance', 'Bootstrapping single Ceph MON') # the following call raises an exception if it can't add the keyring try: ceph.bootstrap_monitor_cluster(leader_get('monitor-secret')) except FileNotFoundError as e: # NOQA -- PEP8 is still PY2 log("Couldn't bootstrap the monitor yet: {}".format(str(e))) return ceph.wait_for_bootstrap() ceph.wait_for_quorum() ceph.create_keyrings() if cmp_pkgrevno('ceph', '12.0.0') >= 0: status_set('maintenance', 'Bootstrapping single Ceph MGR') ceph.bootstrap_manager() # Update client relations notify_client()
def assess_status(): '''Assess status of current unit''' application_version_set(get_upstream_version(VERSION_PACKAGE)) if not config('permit-insecure-cmr'): units = [ unit for rtype in relations() for relid in relation_ids(reltype=rtype) for unit in related_units(relid=relid) if is_cmr_unit(unit) ] if units: status_set("blocked", "Unsupported CMR relation") return if is_unit_upgrading_set(): status_set( "blocked", "Ready for do-release-upgrade and reboot. " "Set complete when finished.") return # Check that the no-bootstrap config option is set in conjunction with # having the bootstrap-source relation established if not config('no-bootstrap') and is_relation_made('bootstrap-source'): status_set( 'blocked', 'Cannot join the bootstrap-source relation when ' 'no-bootstrap is False') return moncount = int(config('monitor-count')) units = get_peer_units() # not enough peers and mon_count > 1 if len(units.keys()) < moncount: status_set( 'blocked', 'Insufficient peer units to bootstrap' ' cluster (require {})'.format(moncount)) return # mon_count > 1, peers, but no ceph-public-address ready = sum(1 for unit_ready in units.values() if unit_ready) if ready < moncount: status_set('waiting', 'Peer units detected, waiting for addresses') return configured_rbd_features = config('default-rbd-features') if has_rbd_mirrors() and configured_rbd_features: if add_rbd_mirror_features( configured_rbd_features) != configured_rbd_features: # The configured RBD features bitmap does not contain the features # required for RBD Mirroring status_set( 'blocked', 'Configuration mismatch: RBD Mirroring ' 'enabled but incorrect value set for ' '``default-rbd-features``') return try: get_osd_settings('client') except OSD_SETTING_EXCEPTIONS as e: status_set('blocked', str(e)) return # active - bootstrapped + quorum status check if ceph.is_bootstrapped() and ceph.is_quorum(): expected_osd_count = config('expected-osd-count') or 3 if sufficient_osds(expected_osd_count): status_set('active', 'Unit is ready and clustered') else: status_set( 'waiting', 'Monitor bootstrapped but waiting for number of' ' OSDs to reach expected-osd-count ({})'.format( expected_osd_count)) else: # Unit should be running and clustered, but no quorum # TODO: should this be blocked or waiting? status_set('blocked', 'Unit not clustered (no quorum)')