如何使用SD总线获取服务状态?

卡米亚克

我需要从C ++应用程序查询,监视并可能更改一些systemd服务的状态。看起来sd-bus是执行此操作的正确方法,但是我很难找到一个例子。

因此,我该如何:

1)通过sd-bus查询服务的当前状态,类似于systemctl status foo.service

2)监视服务的状态,以便每当服务发生更改时都能得到回调?

3)更改服务状态,类似于systemctl start/stop/restart

谢谢!

斯图尔特

使用sd-busAPI绝对正确(标头#include <systemd/sd-bus.h>

首先,您需要访问总线对象:

我这样做:

Systemctl::Systemctl() :
    m_bus(nullptr)
{
    int r = sd_bus_default_system(&m_bus);

    if (r < 0)
        throw exception("Could not open systemd bus");
}

如果您在打开巴士时遇到问题:

  1. 以root / sudo身份运行
  2. 制定一些polkit策略以授予您的用户/组对此命令的访问权限
  3. 运行_user公交而不是_system公交

完成后,别忘了释放总线:

Systemctl::~Systemctl()
{
    sd_bus_unref(m_bus);
}

现在您有3个问题:

  1. 查询状态

对于每个单元,我都有一个类,将转义的名称(foo_2eservice保留m_name,并在中引用了总线m_bus使用任何属性调用此方法。您似乎对"ActiveState"最感兴趣"SubState"

std::string Unit::GetPropertyString(const std::string& property) const
{
    sd_bus_error err = SD_BUS_ERROR_NULL;
    char* msg = nullptr;
    int r;

    r = sd_bus_get_property_string(m_bus,
        "org.freedesktop.systemd1",
        ("/org/freedesktop/systemd1/unit/" + m_unit).c_str(),
        "org.freedesktop.systemd1.Unit",
        property.c_str(),
        &err,
        &msg);

    if (r < 0)
    {
        std::string err_msg(err.message);
        sd_bus_error_free(&err);

        std::string err_str("Failed to get " + property + " for service "
                            + m_name + ". Error: " + err_msg);

        throw exception(err_str);
    }

    sd_bus_error_free(&err);

    // Free memory (avoid leaking)
    std::string ret(msg);
    free (msg);

    return ret;
}
  1. 监视服务状态:

第一步是设置文件描述符以订阅更改。在这种情况下,您有兴趣订购“ PropertiesChanged”信号。请注意,您将获得任何属性更改的信号,而不仅仅是状态。sd_bus_add_match()通话中,有回调的空间,尽管我还没有尝试过。

void Systemctl::SubscribeToUnitChanges(const std::string& escaped_name)
{
    /* This function is an easier helper, but it as only introduced in systemd 237
     * Stretch is on 232 while buster is on 241 .  Need re replace this as long as
     * we still support stretch
    sd_bus_match_signal(
        m_bus,
        nullptr, // slot
        nullptr, // sender
        std::string("/org/freedesktop/systemd1/unit/" + escaped_name).c_str(), // path
        "org.freedesktop.DBus.Properties", // interface
        "PropertiesChanged", // member
        nullptr, // callback
        nullptr // userdata
    );
    */
    std::string match =  "type='signal'";
        match += ",path='/org/freedesktop/systemd1/unit/" + escaped_name + "'" ;
        match += ",interface='org.freedesktop.DBus.Properties'";
        match += ",member='PropertiesChanged'";

    sd_bus_add_match(
        m_bus,
        nullptr, // slot
        match.c_str(),
        nullptr, // callback
        nullptr // userdata
    );
}

相反,我要做的是定期轮询总线以了解预订的更改并更新每个单元:

bool Systemctl::ProcessBusChanges()
{
    bool changed = false;
    sd_bus_message* msg = nullptr;

    // for each new message
    std::list<std::string> escaped_names;
    while( sd_bus_process(m_bus, &msg) )
    {
        // Note:  Once sd_bus_process returns 0, We are supposed to call
        // sd_bus_wait, or check for changes on sd_bus_get_fd before calling
        // this function again.  We're breaking that rule.  I don't really know
        // the consequences.
        if (msg)
        {
            std::string path = strna( sd_bus_message_get_path(msg) );
            sd_bus_message_unref(msg);

            std::string escaped_name = path.erase(0, path.find_last_of('/')+1 );
            escaped_names.push_back(escaped_name);

            changed = true;
        }
    }

    escaped_names.sort();
    escaped_names.unique();
    for (auto unit : escaped_names)
    {
        auto it = m_units.find(unit);
        if (it != m_units.end())
            it->second.RefreshDynamicProperties();
    }

    return changed;
}

如果它告诉我们总线已更改,那么我继续阅读该总线上所有受监视的单元。

  1. 变更状态

这很容易。我用以下,其中method是一个"StartUnit""StopUnit""RestartUnit"

static void CallMethodSS(sd_bus* bus,
                         const std::string& name,
                         const std::string& method)
{
    sd_bus_error err = SD_BUS_ERROR_NULL;
    sd_bus_message* msg = nullptr;
    int r;

    r = sd_bus_call_method(bus,
        "org.freedesktop.systemd1",         /* <service>   */
        "/org/freedesktop/systemd1",        /* <path>      */
        "org.freedesktop.systemd1.Manager", /* <interface> */
        method.c_str(),                     /* <method>    */
        &err,                               /* object to return error in */
        &msg,                               /* return message on success */
        "ss",                               /* <input_signature (string-string)> */
        name.c_str(),  "replace" );         /* <arguments...> */

    if (r < 0)
    {
        std::string err_str("Could not send " + method +
                            " command to systemd for service: " + name +
                            ". Error: " + err.message );

        sd_bus_error_free(&err);
        sd_bus_message_unref(msg);
        throw exception(err_str);
    }

    // Extra stuff that might be useful:  display the response...
    char* response;
    r = sd_bus_message_read(msg, "o", &response);
    if (r < 0)
    {
      LogError("Failed to parse response message: %s\n", strerror(-r) );
    }

    sd_bus_error_free(&err);
    sd_bus_message_unref(msg);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用IAsyncCollector时如何从配置中获取服务总线主题?

如何使用 kubectl 获取多个服务的状态?

如何在 C# 中使用 .NET API 获取 Azure 服务总线的队列大小

如何在特定时间从服务总线获取消息?

使用 Bicep 以编程方式获取服务总线 SharedAccessKey

如何定期使用多线程获取服务器状态

如何使用Azure服务总线主题完成FIFO

如何在服务总线异常中使用TrackingId?

如何使用MSI从Azure中的VMSS访问服务总线

如何通过Ansible获取服务状态?

Ansible:如何通过Ansible获取服务状态?

如何检查socketcan中的总线状态

使用 powershell 从服务总线队列中获取所有带有信息的消息

如何使用Java获取正在运行或未运行的Terracotta服务器状态代码

如何创建服务总线触发webjob?

如何关闭与Azure服务总线队列的连接?

如何增加Azure服务总线队列大小?

服务总线的消息合同如何版本化?

如何推迟Azure服务总线消息?

如何设置Azure服务总线超时

观看SD总线属性

使用MSI的Azure功能访问服务总线

无法使用 Azure 服务总线发送消息

如何使用解析服务维护状态

如何使用Spring云总线与不被配置服务器控制数据刷新应用实例?

如何使用 Azure Functions 输出绑定设置服务总线消息的 MessageId?

如何使用Azure函数将数据发送到服务总线主题?

如何使用带有Node.js的Azure服务总线监听队列?

如何使用 Spring Cloud Stream Binder 动态创建 Azure 服务总线订阅?