xref: /openbmc/phosphor-bmc-code-mgmt/common/src/software.cpp (revision df628196fbd093943cbdd752cf62b15b620bcd23)
1 #include "software.hpp"
2 
3 #include "device.hpp"
4 #include "software_update.hpp"
5 
6 #include <phosphor-logging/lg2.hpp>
7 #include <sdbusplus/async/context.hpp>
8 #include <xyz/openbmc_project/Association/Definitions/server.hpp>
9 #include <xyz/openbmc_project/Software/Activation/aserver.hpp>
10 #include <xyz/openbmc_project/Software/Update/aserver.hpp>
11 #include <xyz/openbmc_project/State/Host/client.hpp>
12 
13 PHOSPHOR_LOG2_USING;
14 
15 using namespace phosphor::software;
16 using namespace phosphor::software::device;
17 using namespace phosphor::software::config;
18 using namespace phosphor::software::update;
19 
20 const static std::string baseObjPathSoftware = "/xyz/openbmc_project/software/";
21 
22 Software::Software(sdbusplus::async::context& ctx, Device& parent) :
23     Software(ctx, parent, getRandomSoftwareId(parent))
24 {}
25 
26 Software::Software(sdbusplus::async::context& ctx, Device& parent,
27                    const std::string& swid) :
28     SoftwareActivation(ctx, (baseObjPathSoftware + swid).c_str(),
29                        Activation::properties_t{Activations::NotReady,
30                                                 RequestedActivations::None}),
31     objectPath(baseObjPathSoftware + swid), parentDevice(parent), swid(swid),
32     ctx(ctx)
33 {
34     std::string objPath = baseObjPathSoftware + swid;
35 
36     debug("{SWID}: created dbus interfaces on path {OBJPATH}", "SWID", swid,
37           "OBJPATH", objPath);
38 };
39 
40 long int Software::getRandomId()
41 {
42     struct timespec ts;
43     clock_gettime(CLOCK_REALTIME, &ts);
44     unsigned int seed = ts.tv_nsec ^ getpid();
45     srandom(seed);
46     return random() % 10000;
47 }
48 
49 std::string Software::getRandomSoftwareId(Device& parent)
50 {
51     return std::format("{}_{}", parent.config.configName, getRandomId());
52 }
53 
54 sdbusplus::async::task<> Software::createInventoryAssociations(bool isRunning)
55 {
56     debug("{SWID}: setting association definitions", "SWID", swid);
57 
58     std::string endpoint = "";
59 
60     try
61     {
62         endpoint = co_await parentDevice.config.getInventoryItemObjectPath(ctx);
63     }
64     catch (std::exception& e)
65     {
66         error(e.what());
67     }
68 
69     if (!associationDefinitions)
70     {
71         std::string path = objectPath;
72         associationDefinitions =
73             std::make_unique<SoftwareAssociationDefinitions>(
74                 ctx, path.c_str(),
75                 SoftwareAssociationDefinitions::properties_t{{}});
76     }
77 
78     if (endpoint.empty())
79     {
80         co_return;
81     }
82 
83     std::vector<std::tuple<std::string, std::string, std::string>> assocs;
84 
85     if (isRunning)
86     {
87         debug("{SWID}: creating 'running' association to {OBJPATH}", "SWID",
88               swid, "OBJPATH", endpoint);
89         std::tuple<std::string, std::string, std::string> assocRunning = {
90             "running", "ran_on", endpoint};
91         assocs.push_back(assocRunning);
92     }
93     else
94     {
95         debug("{SWID}: creating 'activating' association to {OBJPATH}", "SWID",
96               swid, "OBJPATH", endpoint);
97         std::tuple<std::string, std::string, std::string> assocActivating = {
98             "activating", "activated_on", endpoint};
99         assocs.push_back(assocActivating);
100     }
101 
102     associationDefinitions->associations(assocs);
103 
104     co_return;
105 }
106 
107 void Software::setVersion(const std::string& versionStr,
108                           SoftwareVersion::VersionPurpose versionPurpose)
109 {
110     debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr);
111 
112     if (!version)
113     {
114         version = std::make_unique<SoftwareVersion>(
115             ctx, objectPath.str.c_str(),
116             SoftwareVersion::properties_t{versionStr, versionPurpose});
117         version->emit_added();
118         return;
119     }
120 
121     version->version(versionStr);
122     version->purpose(versionPurpose);
123 }
124 
125 SoftwareVersion::VersionPurpose Software::getPurpose()
126 {
127     return version->purpose();
128 }
129 
130 void Software::setActivationBlocksTransition(bool enabled)
131 {
132     if (!enabled)
133     {
134         activationBlocksTransition = nullptr;
135         return;
136     }
137 
138     std::string path = objectPath;
139     activationBlocksTransition =
140         std::make_unique<SoftwareActivationBlocksTransition>(ctx, path.c_str());
141 }
142 
143 void Software::setActivation(SoftwareActivation::Activations act)
144 {
145     activation(act);
146 }
147 
148 void Software::enableUpdate(
149     const std::set<RequestedApplyTimes>& allowedApplyTimes)
150 {
151     if (updateIntf != nullptr)
152     {
153         error("[Software] update of {OBJPATH} has already been enabled",
154               "OBJPATH", objectPath);
155         return;
156     }
157 
158     debug(
159         "[Software] enabling update of {OBJPATH} (adding the update interface)",
160         "OBJPATH", objectPath);
161 
162     updateIntf = std::make_unique<SoftwareUpdate>(ctx, objectPath.str.c_str(),
163                                                   *this, allowedApplyTimes);
164 }
165