明确的用户消息

https://blueprints.launchpad.net/cinder/+spec/better-user-message

使用 ‘action’(动作)、‘resource’(资源)、‘message’(消息)来替换用户消息中的 ‘event’(事件)。

问题描述

我们从 Ocata 版本开始引入了用户消息,这是一个有益的功能,因为它解决了异步任务失败时我们无法提供足够消息的问题(尤其是在卷和快照资源方面)。通过我们新的消息 API,很容易查明任务失败的时间和地点。

但是,更好的用户体验完全取决于我们在项目中是否硬编码了足够的用户消息。因此,这就提出了一个新问题,我们如何在不频繁更改代码的情况下添加这些消息,以及如何干净地维护这种“更好的用户体验,但不涉及功能”的代码。

以下是一些我们相关的用户消息代码

# CODE1: defined event ids
UNKNOWN_ERROR = 'VOLUME_000001'
UNABLE_TO_ALLOCATE = 'VOLUME_000002'
ATTACH_READONLY_VOLUME = 'VOLUME_000003'
IMAGE_FROM_VOLUME_OVER_QUOTA = 'VOLUME_000004'
# CODE2: try/except and write the user messages
with excutils.save_and_reraise_exception():
    if isinstance(error, exception.ImageLimitExceeded):
        self.message_api.create(
            context,
            defined_messages.EventIds.IMAGE_FROM_VOLUME_OVER_QUOTA,
            context.project_id,
            resource_type=resource_types.VOLUME,
            resource_uuid=volume_id)

如果我们尝试基于这些预设添加更多用户消息,可能会遇到一些问题。

  • [CODE1]: 我们会重新定义很多相似的事件 ID,例如 UNABLE_CREATE_VOLUME_DRIVER_NOT_READYUNABLE_CREATE_SNAPSHOT_DRIVER_NOT_READYUNABLE_CREATE_BACKUP_DRIVER_NOT_READY,显然它们都是由于相同的错误引起的,并且是在相同的过程中(创建资源)创建的。

  • [CODE2]: 为了获得明确的消息,我们将拥有一堆只关注检测错误类型并写下相应消息的 ‘if/else’ 代码,更糟糕的是,如果异常越来越多,我们必须一次又一次地更新代码。

那么,我们有什么更好的方法来解决这些问题吗?

用例

这里的主要用例是为最终用户提供明确的用户消息,并为 Cinder 开发人员提供更好的维护体验。

提议的变更

拟议的更改是

  • 在用户消息中引入 message(或者将其命名为 detail 以避免混淆),‘message’ 只代表发生了什么(无论错误还是警告),这意味着 QUOTA_EXCEED 是一个有效的值,而 UPLOAD_TO_IMAGE_OVER_QUOTA 则不是。

  • 建立从异常到消息的关系,我们有很多异常可以直接指出发生了什么以及如何修复,但我们无法将这些暴露给最终用户,因为它会暴露一些敏感信息。我们也不能将清理后的消息硬编码到异常中,因为异常是在不同的地方定义的(例如 cinder 异常和驱动程序异常),并且不同的异常可以转换为一个用户消息。因此,我们建议这样做,建立一个从异常 名称messages(上面介绍的)的字典

    # multi_key dictionary
    ['HBSDBusy','XtremIOArrayBusy']: MessageIds.DEVICE_IS_BUSY
    ['ConfigNotFound',
     'ViolinInvalidBackendConfig']: MessageIds.INVALID_CONFIGURATION
    
    message_map = {
    MessageIds.DEVICE_IS_BUSY: _("Backend device is busy at present."),
    MessageIds.INVALID_CONFIGURATION: _("Invalid configuration."),
    }
    ...
    
  • 在用户消息中引入 action。这应该与 messages 一起引入,并且可以使用它来指示消息创建的时间,例如 CREATE_SNAPSHOT_IN_BACKENDUPLOAD_TO_IMAGE

  • 自动生成 event_id,用户消息用于为直接向管理员显示信息的项目构建用户友好的消息。但是,当引用检测、分类和使用我们消息的项目时,event_id 在这种情况下更有用,因此无论我们如何更改底层行为,都应该有 ‘event_id’。与其手动定义和维护这些 event_ids,不如通过 RESOURCEACTIONMESSAGE 的组合来构建它们,例如:

    # This is how we define event currently
    IMAGE_FROM_VOLUME_OVER_QUOTA = 'VOLUME_000004'
    
    # This is how we would build the event_id at response after this change.
    VOLUME_BACKUP_001_0002 : ({PROJECT}_{RESOURCE}_{ACTION_ID}_{MESSAGE_ID})
    

    我们可以获得这些好处

    1. 我们不需要定义那么多事件。(我们只需要定义更少的消息)。

    2. 它在整个 OpenStack 中都是唯一的。

    3. 它易于阅读,易于分类或分析。

备选方案

另一种选择是,我们可以继续以当前的方式添加用户消息 [1]。(可能还有其他替代方案或更好的解决方案,但我没有想出来。)

数据模型影响

需要更新数据库以存储 ‘action_id’ 和 ‘message_id’,我们还可以弃用 ‘event_id’,因为我们可以在任何时候生成它。

REST API 影响

我们没有 API 影响,因为我们没有暴露创建 API。

安全影响

通知影响

其他最终用户影响

性能影响

其他部署者影响

开发人员影响

为了获得更好的体验,开发人员必须在进行任何相关更改时维护从异常到消息的关系。

实现

负责人

主要负责人

tommylikehu(tommylikehu@gmail.com)

工作项

  • 升级数据库以反映新的用户消息对象。

  • 在用户消息 API 中支持 ‘exception’(异常)和 ‘action’(动作)。

  • 添加一些单元测试。

  • 添加数据库迁移脚本。

依赖项

测试

  • 单元测试

文档影响

  • 更新开发人员文档以获取 ‘exception-to-message’(异常到消息)字典。

参考资料