Openwsman 是一个是实现了 Web Services Management Specification 的开源项目,当前的版本支持通用信息模型 (CIM),使得用户可以通过 Web 服务获取以 CIM 模型表示的系统管理对象信息。借助于 Openwsman,CIM 扩展了其应用场景和范围,并且通过 Web Services 的形式简化了客户端。 Openwsman 最新的代码版本基本上支持了所有的 WS-Management 标准中的操作定义,然而有一个非常重要的缺陷依然存在,那就是对于远程方法调用时的参数类型支持不够,当前其只支持字符串类型的参数,然而在 CIM 中的类型多种多样,如何解决这个问题成为了 Openwsman 能否被广泛应用的一个重要基础。在本文中,作者将介绍一种通过代理技术解决这个参数类型问题的方案,同时对 Openwsman 和 Web Service Management specification 做进一步的介绍。
WS-Management 协议和 Openwsman 项目
在计算机系统管理领域,如何提高各个不同厂家和系统平台之间信息的可互操作性,在强调系统整合概念的今天显得尤为重要。 WS-Management 是一个基于 HTTP/SOAP 格式的传输协议,提供了跨平台系统之间以 Web Services 的形式发布信息的能力,通过 WS-Management 定义的标准数据包格式,系统可以相互发送和接收管理信息,并且可以在要管理的目标系统上执行任务。 WS-Management 协议标准由 DMTF 制定发布,DMTF 是一家非营利性的业界成员合作组织,目的是推动系统管理领域的互通性和标准化。 Openwsman 是一个实现了 WS-Management 协议的开源项目,在 Linux 操作系统上,它可以使用 WS-Mangement 协议来发布系统管理信息。
如何使用 Openwsman 管理通用信息模型 (CIM) 数据
通用信息模型是 DMTF 组织制定发布的另一个标准,用来描述系统管理对象信息,简单来说就是对计算机系统管理领域的对象进行了统一的定义和规范,现在,很多业界的大公司如 IBM,HP,Microsoft 等都在其产品中广泛地采用了 CIM 标准。 Openwsman 已经实现了支持系统管理数据为通用信息模型 (CIM) 的对象,它通过一个插件可以把 CIM 对象信息封装进 SOAP 包,通过 Web Services 发布。 DMTF 的标准 CIM binding guidelines 定义了 CIM 信息到 WS-Management 数据信息的对应关系。下图所表示的,就是网络用户通过网络服务获取到目标系统的 CIM 信息流程模块图。
图 1. 整体流程模块
整体的流程模块包括以下几个方面:
- 系统管理员 (Web user):系统管理员可以通过任何的网页浏览器发送和接收 HTTP/SOAP 数据,这些 SOAP 数据应该完全符合 WS-Management 协议标准的定义;
- Web Server 与 Openwsman:开源项目 Openwsman 依照 WS-Management 协议对下层的信息数据进行 SOAP 格式的封装,并通过 Web Server 发布;或者从 Web Server 获取 HTTP/SOAP 的请求,对请求进行解释和应答。 Openwsman 实现了一个 CIM 插件,依照 CIM-Binging 协议进行 CIM 对象和 WS-Management 格式的转换;
- CIMOM:CIM 对象管理器,用来和底层的 CIM 对象提供者进行交互,获取 CIM 对象,并接收上层用户请求返回结果。当前有多个已经实现了的开源项目,如 Open Pegasus, Open WBEM 以及 SFCB 等;
- CIM Provider:CIM 对象提供者,和底层系统进行直接交互,获取信息,执行管理命令,它把异构的系统信息进行抽象和封装,以 CIM 对象的形式和 CIMOM 通讯,提供服务。
Openwsman 中存在的参数类型问题
在前面的介绍中提到过,WS-Management 协议提供 web 用户远程调用目标系统上方法的能力,这种方法调用将被 Openwsman 传递给 CIMOM,CIMOM 再去调用相应的 CIM 提供者完成最终的任务。 CIM 定义的方法参数类型多种多样,包括 INT, DATETIME, REFERENC 等等,但是当前的 Openwsman 只支持 String 类型参数,而在实际中对于其他类型参数的需求是广泛的,这样的话 Openwsman 的应用能力就被严重制约了。下面的代码来自 Openwsman,可以看到 Openwsman 在处理方法参数的时候并没有进行类型判断,而是直接选择把参数都归为 String 类型。
清单 1. Openwsman 代码片段
static void cim_add_keys(CMPIObjectPath * objectpath, hash_t * keys) { hscan_t hs; hnode_t *hn; if (keys == NULL) { return; } hash_scan_begin(&hs, keys); while ((hn = hash_scan_next(&hs))) { CMAddKey(objectpath, (char *) hnode_getkey(hn), (char *) hnode_get(hn), CMPI_chars); } } |
从上面的代码中,可以看到所有的方法类型参数都被硬编码成 CMPI_chars ,就是 CIM 中的 String 类型。下面我们通过一个测试来实际演示一下这个问题。KVM_ComputerSystem是一个 CIM 方法提供者,这个类包含了一个方法RequestStateChange,这个方法的作用是改变 KVM 虚拟机的电源状态,定义如下所示:
清单 2. RequestStateChange 方法的 MOF 定义
uint32RequestStateChange( uint16 RequestedState CIM_ConcreteJob REF Job datetime TimeoutPeriod ) |
这个方法至少需要提供两个参数,RequestedState,TimeoutPeriod,类型分别是 uint16 和 datetime 类型。为了简化实例,突出重点,我们采用 Openwsman 自带的一个客户端程序来调用上面的方法,省略了 Web server 和 web 页面的构建。这个客户端可以通过命令行参数构建符合 WS-Management 协议的 SOAP 包,直接和 Openwsman 自带的 8889 端口通信。命令如下所示:
清单 3. 使用 Openwsman 客户端程序调用 RequestStateChange 方法
wsman invoke -N root/virt -a RequestStateChange -k RequestedState=1 – k TimeoutPeriod=0 -h localhost -P 8889 -u wsman -p password 'http://vsm.net/kvm/KVM_ComputerSystem' |
http://vsm.net/kvm/KVM_ComputerSystem是我们要调用的目标系统对象,其它参数意义为:
- -N: CIM 信息提供者的名称空间
- -a: 方法名
- -k: 方法参数名和值
- -h: Openwsman 所在的目标系统地址
- -P: 监听端口
- -u: Openwsman 用户名
- -p: Openwsman 密码
上面的客户端程序将创建 SOAP 请求,其中方法参数的 XML 片段如下所示:
清单 4. RequestStateChange 方法参数的 XML 片段
<n1:RequestStateChange_INPUT> <n1:RequestedState>1</n1:RequestedState> <n1:TimeoutPeriod>0</n1:TimeoutPeriod> </n1:RequestStateChange_INPUT> |
可见所有的参数都没有带任何的类型信息。这段 SOAP 请求经过 Openwsman 的解析和重构,将以 CIM-XML 的格式发往下面的 CIMOM,我们使用 SFCB 作为本次实验的 CIMOM,下面的图片显示了发给 SFCB 的 CIM-XML 文件信息:
图 2. Openwsman 创建的 CIM-XML 文件
上图中用红笔标出来的字段显示了 Openwsman 将两个方法参数都设置为 String 类型。 SFCB 在收到这个错误的请求后调用下面的 CIM 方法提供者也会出错,出错信息返回给 Openwsman,显示为下图所示:
图 3. Openwsman 报告的错误日志
如上图所示,方法的参数类型错误会导致方法无法执行。在实际应用中,方法参数类型全部为 String 的情况只占很小一部分,同时因为开源代码的版权问题,应用者不能随意进行修改,以免出现任何开源代码污染的问题。如果想提高 Openwsman 的可用性,同时又不用修改开源代码,有什么好的解决办法呢?答案之一就是可以使用代理技术,通过创建代理 CIM 方法提供者,接受单一的 String 类型参数,根据 MOF 定义转换为正确的类型,再调用实际的 CIM 方法提供者。下面我们来进行详细介绍。
使用代理技术解决问题
在计算机科学中代理模式可以用下面的图表示:
图 4. 代理模式
Proxy 类和 RealSubject 类将实现共同的接口,客户程序调用 Proxy 对象,Proxy 对象再将请求解析封装发给真实的接收者。这个过程中,Proxy 对象需要满足的就是客户的调用接口,并且有能力对数据请求进行转换,以满足真实接收者的要求。把这种设计模式应用在我们的方案中,可以有下面的对应关系:
- Client:CIMOM
- Subject:CMPI 接口
- Proxy:CIM 代理提供者
- RealProxy:真实的 CIM 提供者
这样,加入新的代理层之后,整体流程模块可以表述如下
图 5. 新的整体流程模块
CIM 代理提供者应该满足的接口标准为 DMTF 组织定义的 CMPI 接口,创建 CIM 代理提供者应该至少包括下面两个步骤 :
- 为这个 CIM 代理提供者定义 MOF 格式的类定义
- 为这个 CIM 代理提供者编写代码
清单 5. CIM 代理提供者的 MOF 格式类定义
class Proxy_ComputerSystem: CIM_ComputerSystem { uint32 RequestStateChangeAdapter( [In]string Name, [In]string CreationClassName, [In]string RequestedState, [In]string TimeoutPeriod); }; |
上述方法有四个参数,其中 Name 为真实 CIM 提供者对象的关键字,CreationClassName 为真实 CIM 提供者的类名,代理 CIM 提供者将由这两个参数找到真实的 CIM 提供者,注意关键字参数根据不同的代理目标而有不同。另外两个参数就是我们熟悉的真实 CIM 提供者的方法参数了,只不过类型都被定义为 String 类型,代理 CIM 提供者将负责把这两个参数转换成正确的方法参数类型,传递给真实的 CIM 提供者。这个过程不会涉及到任何对 Openwsman 的修改。 CIM 代理提供者的程序实现如下: