xref: /openbmc/phosphor-bmc-code-mgmt/common/src/software.cpp (revision dbb7015e93b1170465efa9c38ce9ab5a317d190e)
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 
Software(sdbusplus::async::context & ctx,Device & parent)22 Software::Software(sdbusplus::async::context& ctx, Device& parent) :
23     Software(ctx, parent, getRandomSoftwareId(parent))
24 {}
25 
Software(sdbusplus::async::context & ctx,Device & parent,const std::string & swid)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     parentDevice(parent), swid(swid), objectPath(baseObjPathSoftware + swid),
32     ctx(ctx)
33 {
34     std::string objPath = baseObjPathSoftware + swid;
35 
36     emit_added();
37 
38     debug("{SWID}: created dbus interfaces on path {OBJPATH}", "SWID", swid,
39           "OBJPATH", objPath);
40 };
41 
getRandomId()42 long int Software::getRandomId()
43 {
44     struct timespec ts;
45     clock_gettime(CLOCK_REALTIME, &ts);
46     unsigned int seed = ts.tv_nsec ^ getpid();
47     srandom(seed);
48     return random() % 10000;
49 }
50 
getRandomSoftwareId(Device & parent)51 std::string Software::getRandomSoftwareId(Device& parent)
52 {
53     return std::format("{}_{}", parent.config.configName, getRandomId());
54 }
55 
createInventoryAssociations(bool isRunning)56 sdbusplus::async::task<> Software::createInventoryAssociations(bool isRunning)
57 {
58     debug("{SWID}: setting association definitions", "SWID", swid);
59 
60     std::string endpoint = "";
61 
62     try
63     {
64         endpoint = co_await parentDevice.config.getInventoryItemObjectPath(ctx);
65     }
66     catch (std::exception& e)
67     {
68         error("Failed to create association with {ERROR}", "ERROR", e.what());
69         co_return;
70     }
71 
72     if (endpoint.empty())
73     {
74         co_return;
75     }
76 
77     createInventoryAssociation(isRunning, endpoint);
78 }
79 
createInventoryAssociation(bool isRunning,std::string objectPath)80 void Software::createInventoryAssociation(bool isRunning,
81                                           std::string objectPath)
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", objectPath);
89         std::tuple<std::string, std::string, std::string> assocRunning = {
90             "running", "ran_on", objectPath};
91         assocs.push_back(assocRunning);
92     }
93     else
94     {
95         debug("{SWID}: creating 'activating' association to {OBJPATH}", "SWID",
96               swid, "OBJPATH", objectPath);
97         std::tuple<std::string, std::string, std::string> assocActivating = {
98             "activating", "activated_on", objectPath};
99         assocs.push_back(assocActivating);
100     }
101 
102     if (associationDefinitions)
103     {
104         associationDefinitions->associations(assocs);
105     }
106     else
107     {
108         associationDefinitions =
109             std::make_unique<SoftwareAssociationDefinitions>(
110                 ctx, Software::objectPath.str.c_str(),
111                 SoftwareAssociationDefinitions::properties_t{assocs});
112         associationDefinitions->emit_added();
113     }
114 }
115 
setVersion(const std::string & versionStr,SoftwareVersion::VersionPurpose versionPurpose)116 void Software::setVersion(const std::string& versionStr,
117                           SoftwareVersion::VersionPurpose versionPurpose)
118 {
119     debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr);
120 
121     if (!version)
122     {
123         version = std::make_unique<SoftwareVersion>(
124             ctx, objectPath.str.c_str(),
125             SoftwareVersion::properties_t{versionStr, versionPurpose});
126         version->emit_added();
127         return;
128     }
129 
130     version->version(versionStr);
131     version->purpose(versionPurpose);
132 }
133 
getPurpose()134 std::optional<SoftwareVersion::VersionPurpose> Software::getPurpose()
135 {
136     if (!version)
137     {
138         return std::nullopt;
139     }
140     return version->purpose();
141 }
142 
setActivationBlocksTransition(bool enabled)143 void Software::setActivationBlocksTransition(bool enabled)
144 {
145     if (!enabled)
146     {
147         activationBlocksTransition = nullptr;
148         return;
149     }
150 
151     std::string path = objectPath;
152     activationBlocksTransition =
153         std::make_unique<SoftwareActivationBlocksTransition>(ctx, path.c_str());
154 
155     activationBlocksTransition->emit_added();
156 }
157 
setActivation(SoftwareActivation::Activations act)158 void Software::setActivation(SoftwareActivation::Activations act)
159 {
160     activation(act);
161 }
162 
enableUpdate(const std::set<RequestedApplyTimes> & allowedApplyTimes)163 void Software::enableUpdate(
164     const std::set<RequestedApplyTimes>& allowedApplyTimes)
165 {
166     if (updateIntf != nullptr)
167     {
168         error("[Software] update of {OBJPATH} has already been enabled",
169               "OBJPATH", objectPath);
170         return;
171     }
172 
173     debug(
174         "[Software] enabling update of {OBJPATH} (adding the update interface)",
175         "OBJPATH", objectPath);
176 
177     updateIntf = std::make_unique<SoftwareUpdate>(ctx, objectPath.str.c_str(),
178                                                   *this, allowedApplyTimes);
179 }
180