背景

运维工作并不总是在浏览器里完成,很多时候,排障发生在需要快速查询、快速执行命令的场景中。这个时候,CLI 往往比 Web 页面更直接。并且,CLI更适合agent的工作。本次我着手CLI的初步构建。

CLI的特点有:

  • 纯文本交互:没有图形界面(GUI)的窗口、按钮或图标,全靠输入指令。

  • 高控制力:一条命令可以完成复杂的操作,支持脚本自动化(批量执行多条命令)。

  • 低资源占用:不需要渲染图形,对系统资源要求极低。

  • 可脚本化:可以将一系列命令写成脚本文件(如 .sh.bat),实现重复任务的自动执行。

目标

这个 CLI 的第一阶段目标并不复杂,主要解决几个最基本的问题:

  • 登录系统
  • 保存本地登录状态
  • 查询主机列表
  • 查询告警列表
  • 搜索日志
  • 查看当前登录用户

因此,第一版 CLI 的命令设计如下:

monitor login -u admin2 -p 123456  #登录系统

monitor whoami  #查看当前用户

monitor hosts list  #查看主机列表                            #

monitor alerts list  #查看告警列表

monitor logs search --level ERROR  #查询错误日志

monitor logout  #退出登录

目录结构设计

monitor-cli/
├── package.json
└── src/
    ├── index.js
    ├── commands/
    │   ├── login.js
    │   ├── logout.js
    │   ├── whoami.js
    │   ├── hosts.js
    │   ├── alerts.js
    │   └── logs.js
    └── lib/
        ├── config.js
        ├── http.js
        ├── output.js
        ├── session.js
        └── mock-data.js

设计思路:

  • index.js负责注册命令
  • commands/负责命令定义和调用
  • lib/负责通用能力,如配置、认证、输出、请求

核心代码

整个工具分成三层:入口层负责注册命令,命令层负责参数和动作,底层库负责配置、认证和输出。后续增加新命令和替换真实接口不用推翻原有结构。

const program = new Command()

program
  .name('monitor')
  .description('运维监控命令行客户端')
  .version('0.1.0')

registerLoginCommand(program)
registerLogoutCommand(program)
registerWhoamiCommand(program)
registerHostsCommand(program)
registerAlertsCommand(program)
registerLogsCommand(program)

program.parseAsync(process.argv)

CLI 没有浏览器环境,不能使用 localStorage,所以改成把 token 和用户信息写入本地配置文件。同时登录校验统一收口成一个函数,让所有查询类命令都能复用。

const CONFIG_PATH = path.join(os.homedir(), '.monitor-cli', 'config.json')

export function readConfig() {
  if (!fs.existsSync(CONFIG_PATH)) {
    writeConfig(defaultConfig)
    return { ...defaultConfig }
  }
  return { ...defaultConfig, ...JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')) }
}

export function requireAuth() {
  const config = readConfig()
  if (!config.token) {
    throw new Error('请先执行 monitor login')
  }
  return config
}

在命令设计上,贴近真实运维操作,例如 hosts list、alerts list、logs search。每个命令本身都很简单,只做校验登录、处理数据、格式化输出。

hostsCommand
  .command('list')
  .description('查看主机列表')
  .action(() => {
    requireAuth()
    printTable(
      ['主机名', 'IP', '状态', 'CPU', '内存'],
      hosts.map(item => [item.hostname, item.ip, item.status, item.cpu, item.mem])
    )
  })

界面展示

(图中为模拟数据)

后续方向

1. 接真实后端接口

把当前的 mock 登录和 mock 数据替换成实际的 API 请求,例如:

const client = createHttpClient()

const result = await client.get('/hosts')

2. 增加交互式输入

例如后续可以把:

monitor login -u admin2 -p 123456

改造成:

monitor login

然后在终端里提示输入用户名和密码。

3. 增加更多运维操作

例如:

monitor alerts resolve --id 3

monitor hosts detail --name db-server-01

monitor config set-base-url http://127.0.0.1:5000/api

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐