暂停带有从属 hacluster 的 Charm,避免发送错误警报

总体目标是留下“警告”警报,而不是“严重”警报,这将帮助人工操作员理解所有服务并非完全健康,同时减少由于正在进行的操作引起的关键性。当维护操作下的服务恢复正常(恢复)时,Nrpe 检查将被重新配置。

暂停/恢复单元时将应用以下逻辑

  • 暂停主单元,暂停从属 hacluster;

  • 恢复主单元,恢复从属 hacluster;

  • 暂停 hacluster 单元,暂停主单元;

  • 恢复 hacluster 单元,恢复主单元;

问题描述

我们需要停止在 Openstack charm 单元的 hacluster 从属单元暂停时,或者主单元也暂停进行维护时发送错误警报。这可能有助于运维接收更有效的警报。

有几个使用 hacluster 和 NRPE 的 charm 可以从中受益

  • charm-ceilometer

  • charm-ceph-radosgw

  • charm-designate

  • charm-keystone

  • charm-neutron-api

  • charm-nova-cloud-controller

  • charm-openstack-dashboard

  • charm-cinder

  • charm-glance

  • charm-heat

  • charm-swift-proxy

暂停主单元

例如,如果部署了 3 个 keystone 单元(keystone/0、keystone/1 和 keystone/2),并且 keystone/0 被暂停

1) 其他单元(keystone/1 和 keystone/2)上的 haproxy_servers 将发出警报,因为 keystone/0 上的 apache2 服务已停止

  1. keystone/0 中的 haproxy、apache2.service 和 memcached.service 也会发出警报

3) 有可能 corosync 和 pacemaker 将 VIP 放置在同一个单元上,此时服务将失败,因为 haproxy 已禁用。因此,hacluster 从属单元也应暂停。

注意:暂停主单元时受影响的服务可能会因主 charm 而异

暂停 hacluster 单元

暂停 hacluster 将集群节点(例如 keystone)设置为待机模式。待机节点将停止其资源(hacluster、apache2),这将触发错误警报。为了解决此问题,hacluster 的单元应告知 keystone 单元它们已暂停。一种方法是通过 ha 关系来实现。

提议的变更

暂停暂停主单元

主单元上的暂停操作应与其对等单元共享该事件,以修改它们上的行为(直到触发恢复操作)。它还应将状态(暂停/恢复)共享给从属单元,以便能够同步相同的状态。

主单元中的 actions.py 文件

def pause(args):
    pause_unit_helper(register_configs())

    # Logic added to share the event with peers
    inform_peers_if_ready(check_api_unit_ready)
    if is_nrpe_joined():
      update_nrpe_config()

    # logic added to inform hacluster subordinate unit has been paused
    relid = relation_ids('ha')
    for r_id in relid:
        relation_set(relation_id=r_id, paused=True)

def resume(args):
    resume_unit_helper(register_configs())

    # Logic added to share the event with peers
    inform_peers_if_ready(check_api_unit_ready)
    if is_nrpe_joined():
      update_nrpe_config()

    # logic added to inform hacluster subordinate unit has been resumed
    relid = relation_ids('ha')
    for r_id in relid:
        relation_set(relation_id=r_id, paused=False)

暂停主单元后,它会将 unit-state-{unit_name} 更改为 NOTREADY。例如

juju show-unit keystone/0 --endpoint cluster
keystone/0:
  workload-version: 17.0.0
  machine: "1"
  opened-ports:
  - 5000/tcp
  public-address: 10.5.2.64
  charm: cs:~openstack-charmers-next/keystone-562
  leader: true
  relation-info:
  - endpoint: cluster
    related-endpoint: cluster
    application-data: {}
    local-unit:
      in-scope: true
      data:
        admin-address: 10.5.2.64
        egress-subnets: 10.5.2.64/32
        ingress-address: 10.5.2.64
        internal-address: 10.5.2.64
        private-address: 10.5.2.64
        public-address: 10.5.2.64
        unit-state-keystone-0: NOTREADY

注意:unit-state-{unit_name} 字段已经实现,我只是建议使用此字段,并在单元暂停时将其值更改为 NOTREADY,并在恢复时返回到 READY。

当每个单元都知道哪个单元已暂停时,可以更改脚本 check_haproxy.sh 以接受一个标志,以警告已暂停的 keystone 单元。bash 脚本现在无法接收标志。

Check_haproxy.sh 可以从 Bash 重写为 Python,以接受一个标志来警告特定的主机名(例如 check_haproxy.py –warning keystone-0)正在维护中。

charmhelpers/contrib/charmsupport 上的 nrpe.py 文件应进行更改,首先检查集群中是否有任何已暂停的单元,然后根据需要添加警告标志

def add_haproxy_checks(nrpe, unit_name):
    """
    Add checks for each service in list

    :param NRPE nrpe: NRPE object to add check to
    :param str unit_name: Unit name to use in check description
    """
    cmd = "check_haproxy.py"

    peers_states = get_peers_unit_state()
    units_not_ready = [
        unit.replace('/', '-')
        for unit, state in peers_states.items()
        if state == UNIT_NOTREADY
    ]

    if is_unit_paused_set():
        units_not_ready.append(local_unit().replace('/', '-'))

    if units_not_ready:
        cmd += " --warning {}".format(','.join(units_not_ready))

    nrpe.add_check(
        shortname='haproxy_servers',
        description='Check HAProxy {%s}' % unit_name,
        check_cmd=cmd)
    nrpe.add_check(
        shortname='haproxy_queue',
        description='Check HAProxy queue depth {%s}' % unit_name,
        check_cmd='check_haproxy_queue_depth.sh')

当主单元更改状态(例如 READY 到 NOTREADY)时,有必要重写集群中其他主单元上的 nrpe 文件,否则它们将无法警告某个单元正在维护中。

负责经典 charm 中钩子的文件

@hooks.hook('cluster-relation-changed')
@restart_on_change(restart_map(), stopstart=True)
def cluster_changed():
    # logic added to update nrpe_config in all principal units when
    # a status is changed
    update_nrpe_config()

注意:在 reactive charm 中,使用处理程序可能会略有不同,但基本思想是在每次集群中的配置发生更改时更新_nrpe_config。这将防止集群中其他单元发出错误警报。

主单元的服务

在单元暂停时删除 /etc/nagios/nrpe.d 中的 .cfg 文件,对于这些服务将停止发送严重错误。这种方法的缺点是它不会在 Nagios 中显示用户友好的消息,说明特定的服务(apache2、memcached 等)正在维护中,但另一方面,它更容易实现。

负责经典 charm 中钩子的文件

@hooks.hook('nrpe-external-master-relation-joined',
            'nrpe-external-master-relation-changed')
def update_nrpe_config():
    # logic before change
    # ...

    nrpe_setup = nrpe.NRPE(hostname=hostname)
    nrpe.copy_nrpe_checks()

    # added logic to remove services
    if is_unit_paused_set():
        nrpe.remove_init_service_checks(
            nrpe_setup,
            _services,
            current_unit
        )

    else:
        nrpe.add_init_service_checks(
            nrpe_setup,
            _services,
            current_unit
        )

    # end of added logic

    nrpe.add_haproxy_checks(nrpe_setup, current_unit)
    nrpe_setup.write()

下面介绍了新的逻辑来删除这些服务。

charmhelpers/contrib/charmsupport/nrpe.py 文件

# added logic to remove apache2, memcached and etc...
def remove_init_service_checks(nrpe, services, unit_name):
    for svc in services:
        if host.init_is_systemd(service_name=svc):
            nrpe.remove_check(
                shortname=svc,
                description='process check {%s}' % unit_name,
                check_cmd='check_systemd.py %s' % svc
            )

服务状态在几分钟后将从 nagios 中消失。当使用恢复操作时,服务最初会恢复为 PENDING,但在几分钟后会进行检查。

暂停 hacluster 单元

charm-hacluster 中的 actions.py 文件

def pause(args):
    """Pause the hacluster services.
    @raises Exception should the service fail to stop.
    """
    pause_unit()
    # logic added to inform keystone that unit has been paused
    relid = relation_ids('ha')
    for r_id in relid:
        relation_set(relation_id=r_id, paused=True)


def resume(args):
    """Resume the hacluster services.
    @raises Exception should the service fail to start."""
    resume_unit()
    # logic added to inform keystone that unit has been resumed
    relid = relation_ids('ha')
    for r_id in relid:
        relation_set(relation_id=r_id, paused=False)

暂停 hacluster 将导致共享一个名为 paused 的新变量,该变量可用于主单元。

负责经典 charm 中钩子的文件

@hooks.hook('ha-relation-changed')
@restart_on_change(restart_map(), restart_functions=restart_function_map())
def ha_changed():

    # Added logic to pause keystone unit when hacluster is paused
    for rid in relation_ids('ha'):
        for unit in related_units(rid):
            paused = relation_get('paused', rid=rid, unit=unit)
            clustered = relation_get('clustered', rid=rid, unit=unit)
            if clustered and is_db_ready():
                if paused == 'True':
                    pause_unit_helper(register_configs())

                elif paused == 'False':
                    resume_unit_helper(register_configs())

                update_nrpe_config()
                inform_peers_if_ready(check_api_unit_ready)
                # inform subordinate unit that is paused or resumed
                relation_set(relation_id=rid, paused=is_unit_paused_set())

通过告知对等单元并更新 nrpe 配置,这将足以触发必要的逻辑来删除服务检查。

在主单元暂停的情况下,hacluster 也应暂停。为了实现这一点,可以使用 charm-ha-cluster 中的 ha-relation-changed

@hooks.hook('ha-relation-joined',
            'ha-relation-changed',
            'peer-availability-relation-joined',
            'peer-availability-relation-changed',
            'pacemaker-remote-relation-changed')
def ha_relation_changed():
    # Inserted logic
    # pauses if the principal unit is paused
    paused = relation_get('paused')
    if paused == 'True':
        pause_unit()
    elif paused == 'False':
        resume_unit()

    # share if the subordinate unit status
    for rel_id in relation_ids('ha'):
        relation_set(
            relation_id=rel_id,
            clustered="yes",
            paused=is_unit_paused_set()
        )

备选方案

主单元服务检查的一种替代方法是更改 charm-nrpe 中的 systemd.py 以接受标志 -w,就像 check_haproxy.py 的建议一样

这样就不需要删除主单元服务的 .cfg 文件,但需要调整函数 add_init_service_checks 以能够接受带有警告标志的服务。

实现

负责人

主要负责人

gabrielcocenza

Gerrit Topic

使用 Gerrit 主题“pausing-charms-hacluster-no-false-alerts”用于与此规范相关的所有补丁。

git-review -t pausing-charms-hacluster-no-false-alerts

工作项

  • charmhelpers

    • nrpe.py

    • check_haproxy.py

  • charm-ceilometer

  • charm-ceph-radosgw

  • charm-designate

  • charm-keystone

  • charm-neutron-api

  • charm-nova-cloud-controller

  • charm-openstack-dashboard

  • charm-cinder

  • charm-glance

  • charm-heat

  • charm-swift-proxy

  • charm-nrpe (替代方案)

    • systemd.py

  • charm-hacluster

    • actions.py

仓库

不需要新的 git 仓库。

文档

有必要记录暂停/恢复从属 hacluster 的影响以及对 Openstack API charm 的副作用。

安全性

没有额外的安全问题。

测试

代码更改将通过单元测试和功能测试覆盖。对于功能测试,它将使用包含 keystone、hacluster、nrpe 和 nagios 的 bundle。

依赖项