summaryrefslogtreecommitdiffstats
path: root/occ_finder.cpp
blob: 0c02c3594fbe6a7eaa004481b5003f596b972eeb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <algorithm>
#include <iterator>
#include <experimental/filesystem>
#include <sdbusplus/server.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
#include "occ_finder.hpp"
#include "config.h"
namespace open_power
{
namespace occ
{
namespace finder
{

using namespace phosphor::logging;

constexpr auto toChar(size_t c)
{
    constexpr auto map = "0123456789abcdef";
    return map[c];
}

template <typename T>
T getDbusProperty(sdbusplus::bus::bus& bus,
                  const std::string& service,
                  const std::string& objPath,
                  const std::string& interface,
                  const std::string& property)
{
    using namespace sdbusplus::xyz::openbmc_project::Common::Error;

    constexpr auto PROPERTY_INTF = "org.freedesktop.DBus.Properties";

    auto method = bus.new_method_call(
                      service.c_str(),
                      objPath.c_str(),
                      PROPERTY_INTF,
                      "Get");
    method.append(interface, property);

    auto reply = bus.call(method);
    if (reply.is_method_error())
    {
         log<level::ERR>("Failed to get property",
                        entry("PROPERTY=%s", property.c_str()),
                        entry("PATH=%s", objPath.c_str()),
                        entry("INTERFACE=%s", interface.c_str()));
        elog<InternalFailure>();
    }

    sdbusplus::message::variant<T> value;
    reply.read(value);

    return sdbusplus::message::variant_ns::get<T>(value);
}

std::vector<std::string> get(sdbusplus::bus::bus& bus)
{
    namespace fs = std::experimental::filesystem;
    using Path = std::string;
    using Service = std::string;
    using Interface = std::string;
    using Interfaces = std::vector<Interface>;

    auto mapper =
        bus.new_method_call(
            "xyz.openbmc_project.ObjectMapper",
            "/xyz/openbmc_project/object_mapper",
            "xyz.openbmc_project.ObjectMapper",
            "GetSubTree");

    auto depth = 0;
    Path path = CPU_SUBPATH;
    Interfaces interfaces
    {
        "xyz.openbmc_project.Inventory.Item",
        "xyz.openbmc_project.State.Decorator.OperationalStatus"
    };

    mapper.append(path);
    mapper.append(depth);
    mapper.append(interfaces);

    auto result = bus.call(mapper);
    if (result.is_method_error())
    {
        // It's okay to not have inventory, for example at BMC standby
        return {};
    }

    using MapperResponse = std::map<Path, std::map<Service, Interfaces>>;
    MapperResponse response;
    result.read(response);
    if (response.empty())
    {
        // It's okay to not have inventory, for example at BMC standby
        return {};
    }

    std::vector<std::string> occs;
    for (auto count = 0; count < MAX_CPUS; ++count)
    {
        fs::path p(path);
        p /= std::string(CPU_NAME) + toChar(count);

        auto entry = response.find(p.string());
        if (response.end() != entry)
        {
            Criteria match{};
            match.emplace_back(std::make_tuple(
                               "xyz.openbmc_project.Inventory.Item",
                               "Present",
                               true));

            // Select only if the CPU is marked 'Present'.
            // Local variable to make it readable
            auto path = entry->first;
            auto service = entry->second.begin()->first;
            if (matchCriteria(bus, path, service, match))
            {
                occs.emplace_back(std::string(OCC_NAME) +
                                  toChar(count));
            }
        }
    }

    return occs;
}

bool matchCriteria(sdbusplus::bus::bus& bus,
                   const std::string& path,
                   const std::string& service,
                   const Criteria& match)
{
    for (const auto& iter: match)
    {
        auto result = getDbusProperty<bool>(bus, service, path,
                                            std::get<0>(iter),
                                            std::get<1>(iter));
        if (result != std::get<2>(iter))
        {
            return false;
        }
    }
    return true;
}

} // namespace finder
} // namespace occ
} // namespace open_power
OpenPOWER on IntegriCloud