调用第三方一定要封装,哪怕仅仅是一个命令行
调用第三方工具一定要封装,哪怕仅仅是一个命令行。封装的好处:应对版本变化、方便做切面、简化使用、提供统一方法。 现象 qemu-img 是一个典型的例子。 为啥要封装? 底层工具版本变化导致的参数校验变化; 方便做切面,可以做一些统计、日志、重试、timeout 等; 简化使用,底层工具参数众多,大部分都用不上; 提供实现目的的统一方法,少即是多,实现一个目的最好只有一种方法。 封装得好是什么样 qemu-img 自认为封装的挺好。 对于一些版本不支持的参数,明确打印出来了,通过 error 日志一眼看出问题,这效率,QA 也能排查了。 比如: logger.error("QemuImg commit: qemu-img commit [-d] not supported") 一个封装示例 class QemuImg(object): """ qemu-img Package """ @classmethod def commit_str(cls, filename, image_opts=None, fmt=None, skip_empty=False, host=None, ): """ qemu-img commit [--object objectdef] [--image-opts] [-q] [-f fmt] [-t cache] [-b base] [-d] [-p] filename The image FILENAME is emptied after the operation has succeeded. If you do not need FILENAME afterwards and intend to drop it, you may skip emptying FILENAME by specifying the -d flag. """ if fmt and fmt not in ["raw", "qcow2"]: logger.error("QemuImg commit: unsupported format: %s" % fmt) return None if image_opts and not isinstance(image_opts, dict): logger.error("QemuImg commit: image_opts must be a dict") return None if skip_empty: has_d_cmd = r'qemu-img -h | grep commit | grep "\-d"' ret = exec_cmd(has_d_cmd, remote_host=host) if not is_cmd_ok(ret): logger.error("QemuImg commit: qemu-img commit [-d] not supported") return None cmd_str = "qemu-img commit" if fmt: cmd_str += " -f %s" % fmt if skip_empty: cmd_str += " -d" if image_opts: image_opts_str_li = ["%s=%s" % (key, value) for key, value in image_opts.items()] if image_opts_str_li: cmd_str += " --image-opts %s" % ",".join(image_opts_str_li) if filename: cmd_str += " %s" % filename logger.info("QemuImg commit cmd: %s", cmd_str) return cmd_str 小结 调用第三方工具一定要封装,哪怕仅仅是一个命令行; 封装应对版本变化、方便做切面、简化使用、提供统一方法; 对于版本不支持的参数,明确打印出来,QA 也能排查; 少即是多,实现一个目的最好只有一种方法。