ceph源码分析--admin socket

本文深入解析了 Ceph 存储系统中 Monitor 组件的工作原理及实现细节,包括其核心流程、服务线程启动机制及 Admin Socket 的初始化过程。

官方文档

http://docs.ceph.com/docs/master/rados/operations/monitoring/

具体用法

ceph daemon {daemon-name}
ceph daemon {path-to-socket-file}

ceph daemon osd.0 foo
ceph daemon /var/run/ceph/ceph-osd.0.asok foo

很多组件都可以通过命令,本文主要讲解Monitor部分
根据作者的理解这其实是一种UNIX Domain Socket IPC,具体的介绍可参阅《Unix环境高级编程》书籍

主要流程

这里写图片描述

common_init_finish(g_ceph_context);

void common_init_finish(CephContext *cct)

void common_init_finish(CephContext *cct)
{
  cct->init_crypto();
  ZTracer::ztrace_init();

  int flags = cct->get_init_flags();
  if (!(flags & CINIT_FLAG_NO_DAEMON_ACTIONS))
    //启动服务线程
    cct->start_service_thread();

  if ((flags & CINIT_FLAG_DEFER_DROP_PRIVILEGES) &&
      (cct->get_set_uid() || cct->get_set_gid())) {
    cct->get_admin_socket()->chown(cct->get_set_uid(), cct->get_set_gid());
  }

  md_config_t *conf = cct->_conf;

  if (!conf->admin_socket.empty() && !conf->admin_socket_mode.empty()) {
    int ret = 0;
    std::string err;

    ret = strict_strtol(conf->admin_socket_mode.c_str(), 8, &err);
    if (err.empty()) {
      if (!(ret & (~ACCESSPERMS))) {
        cct->get_admin_socket()->chmod(static_cast<mode_t>(ret));
      } else {
        lderr(cct) << "Invalid octal permissions string: "
            << conf->admin_socket_mode << dendl;
      }
    } else {
      lderr(cct) << "Invalid octal string: " << err << dendl;
    }
  }
}

start_service_thread()

void CephContext::start_service_thread()
{
  ceph_spin_lock(&_service_thread_lock);
  if (_service_thread) {
    ceph_spin_unlock(&_service_thread_lock);
    return;
  }
  _service_thread = new CephContextServiceThread(this);
  _service_thread->create("service");
  ceph_spin_unlock(&_service_thread_lock);

  // make logs flush on_exit()
  if (_conf->log_flush_on_exit)
    _log->set_flush_on_exit();

  // Trigger callbacks on any config observers that were waiting for
  // it to become safe to start threads.
  _conf->set_val("internal_safe_to_start_threads", "true");
  _conf->call_all_observers();

  // start admin socket
  if (_conf->admin_socket.length())
    //初始化
    _admin_socket->init(_conf->admin_socket);
}

AdminSocket::init(const std::string &path)

bool AdminSocket::init(const std::string &path)
{
  ldout(m_cct, 5) << "init " << path << dendl;

  /* Set up things for the new thread */
  std::string err;
  int pipe_rd = -1, pipe_wr = -1;
  //创建管道用于关闭
  err = create_shutdown_pipe(&pipe_rd, &pipe_wr);
  if (!err.empty()) {
    lderr(m_cct) << "AdminSocketConfigObs::init: error: " << err << dendl;
    return false;
  }
  int sock_fd;
  //绑定监听
  err = bind_and_listen(path, &sock_fd);
  if (!err.empty()) {
    lderr(m_cct) << "AdminSocketConfigObs::init: failed: " << err << dendl;
    close(pipe_rd);
    close(pipe_wr);
    return false;
  }

  /* Create new thread */
  m_sock_fd = sock_fd;
  m_shutdown_rd_fd = pipe_rd;
  m_shutdown_wr_fd = pipe_wr;
  m_path = path;

  m_version_hook = new VersionHook;
  register_command("0", "0", m_version_hook, "");
  register_command("version", "version", m_version_hook, "get ceph version");
  register_command("git_version", "git_version", m_version_hook, "get git sha1");
  m_help_hook = new HelpHook(this);
  register_command("help", "help", m_help_hook, "list available commands");
  m_getdescs_hook = new GetdescsHook(this);
  register_command("get_command_descriptions", "get_command_descriptions",
           m_getdescs_hook, "list available commands");
  //创建一个线程,运行entry()
  create("admin_socket");
  add_cleanup_file(m_path.c_str());
  return true;
}

AdminSocket::entry()

void* AdminSocket::entry()
{
  ldout(m_cct, 5) << "entry start" << dendl;
  while (true) {
    struct pollfd fds[2];
    memset(fds, 0, sizeof(fds));
    fds[0].fd = m_sock_fd;
    fds[0].events = POLLIN | POLLRDBAND;
    fds[1].fd = m_shutdown_rd_fd;
    fds[1].events = POLLIN | POLLRDBAND;
    //poll轮询
    int ret = poll(fds, 2, -1);
    if (ret < 0) {
      int err = errno;
      if (err == EINTR) {
    continue;
      }
      lderr(m_cct) << "AdminSocket: poll(2) error: '"
           << cpp_strerror(err) << dendl;
      return PFL_FAIL;
    }

    if (fds[0].revents & POLLIN) {
      // Send out some data
      //处理请求
      do_accept();
    }
    if (fds[1].revents & POLLIN) {
      // Parent wants us to shut down
      //父进程希望关闭
      return PFL_SUCCESS;
    }
  }
  ldout(m_cct, 5) << "entry exit" << dendl;
}

AdminSocket::do_accept()

while (1) {
    //读取命令
    int ret = safe_read(connection_fd, &cmd[pos], 1);
    if (ret <= 0) {
      if (ret < 0) {
        lderr(m_cct) << "AdminSocket: error reading request code: "
             << cpp_strerror(ret) << dendl;
      }
···
//寻找对应的hook
while (match.size()) {
    p = m_hooks.find(match);
    if (p != m_hooks.end())
      break;

    // drop right-most word
    size_t pos = match.rfind(' ');
    if (pos == std::string::npos) {
      match.clear();  // we fail
      break;
    } else {
      match.resize(pos);
    }
  }
···
    in_hook = true;
    auto match_hook = p->second;
    m_lock.Unlock();
    //调用子类的call函数
    bool success = match_hook->call(match, cmdmap, format, out);
    m_lock.Lock();
···
//返回结果
int ret = safe_write(connection_fd, &len, sizeof(len));
  ···
if (out.write_fd(connection_fd) >= 0)
<think>我们正在分析用户的问题:用户想判断命令`ceph-deploy ceph-admin01 ceph-node01 ceph-node02 ceph-node03`是否缺少参数。 首先,我们需要了解`ceph-deploy`命令的基本结构。根据引用[2]中提供的帮助信息,`ceph-deploy`命令需要指定一个子命令(如`mds`、`admin`等),然后才是主机名。 引用[2]的示例:`ceph-deploy mds create ...`,这里`mds`是子命令,`create`是子命令下的动作。 用户给出的命令格式为:`ceph-deploy ceph-admin01 ceph-node01 ceph-node02 ceph-node03` 这个命令中,第一个参数是`ceph-admin01`,后面是三个节点。但是,这里并没有指定子命令,因此这个命令是不完整的。 我们再参考引用[1]中使用的`ceph-deploy`命令: `cephadmin@ceph-deploy:/home/ceph/ceph-cluster$ ceph-deploy admin ceph-node1 ceph-node2 ceph-node3 ceph-node4` 这里,`admin`是子命令,后面跟主机名。 因此,我们可以得出结论:用户命令缺少子命令(如`admin`、`install`、`osd`等)。 所以,正确的命令应该包含一个子命令,例如: `ceph-deploy admin ceph-admin01 ceph-node01 ceph-node02 ceph-node03` 或者根据实际需要选择其他子命令。 注意事项:`ceph-admin01`通常作为管理节点,但在这里它被当作主机名传递,所以如果这个节点也需要执行管理命令,那么它也应该被包含在参数中。但是命令缺少子命令是主要问题。 因此,回答用户:该命令缺少子命令,需要指定子命令(如`admin`)才能执行。 </think> 根据您提供的命令`ceph-deploy ceph-admin01 ceph-node01 ceph-node02 ceph-node03`和Ceph部署规范分析: ### 命令分析 1. **缺少子命令** `ceph-deploy`必须跟随明确的**子命令**(如`admin`、`install`、`osd`等)才能执行具体操作。引用[2]明确指出: ```bash usage: ceph-deploy mds [-h] {create} ... ``` 该格式要求先指定操作类型(如`admin`),再跟节点列表[^2]。 2. **参数顺序错误** 正确格式应为: ```bash ceph-deploy [子命令] [节点列表] ``` 您的命令将`ceph-admin01`(可能是管理节点)误放在子命令位置。 3. **正确命令示例** 参考引用[1]的规范格式: ```bash ceph-deploy admin ceph-node1 ceph-node2 ceph-node3 ceph-node4 # admin是子命令 ``` ### 解决方案 需要添加子命令并调整顺序,例如: ```bash ceph-deploy admin ceph-admin01 ceph-node01 ceph-node02 ceph-node03 ``` 或根据实际需求选择子命令: ```bash # 部署MON监控节点 ceph-deploy mon create ceph-node01 ceph-node02 # 部署OSD存储 ceph-deploy osd create ceph-node03 --data /dev/sdb ``` ### 验证方法 通过帮助命令查看完整语法: ```bash ceph-deploy --help # 查看所有子命令 ceph-deploy admin --help # 查看具体用法 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值