Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
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)
Beispiel #4
0
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())))
Beispiel #5
0
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()
Beispiel #6
0
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)')