Line data Source code
1 : /**
2 : * @file dalMethods.cxx
3 : *
4 : * Implementations of Methods defined in confmodel schema classes
5 : *
6 : * This is part of the DUNE DAQ Software Suite, copyright 2020.
7 : * Licensing/copyright details are in the COPYING file that you should have
8 : * received with this code.
9 : */
10 :
11 : #include "confmodel/Application.hpp"
12 : #include "confmodel/confmodelIssues.hpp"
13 : #include "confmodel/DaqApplication.hpp"
14 : #include "confmodel/DaqModule.hpp"
15 : #include "confmodel/DetDataSender.hpp"
16 : #include "confmodel/DetDataReceiver.hpp"
17 : #include "confmodel/DetectorToDaqConnection.hpp"
18 : #include "confmodel/DetectorStream.hpp"
19 : #include "confmodel/Jsonable.hpp"
20 : #include "confmodel/OpMonURI.hpp"
21 : #include "confmodel/PhysicalHost.hpp"
22 : #include "confmodel/RCApplication.hpp"
23 : #include "confmodel/Resource.hpp"
24 : #include "confmodel/ResourceSet.hpp"
25 : #include "confmodel/Segment.hpp"
26 : #include "confmodel/Session.hpp"
27 : #include "confmodel/Service.hpp"
28 : #include "confmodel/VirtualHost.hpp"
29 :
30 : #include "confmodel/test_circular_dependency.hpp"
31 :
32 : #include "nlohmann/json.hpp"
33 : #include "conffwk/ConfigObject.hpp"
34 : #include "conffwk/Configuration.hpp"
35 : #include "conffwk/Schema.hpp"
36 :
37 : #include <list>
38 : #include <set>
39 : #include <iostream>
40 :
41 : using namespace dunedaq::conffwk;
42 :
43 :
44 : // Stolen from ATLAS dal package
45 : namespace {
46 : /**
47 : * Static function to calculate list of components
48 : * from the root segment to the lowest component which
49 : * the child object (a segment or a resource) belongs.
50 : */
51 :
52 : void
53 0 : make_parents_list(
54 : const ConfigObjectImpl * child,
55 : const dunedaq::confmodel::ResourceSet * resource_set,
56 : std::vector<const dunedaq::confmodel::Resource *> & p_list,
57 : std::list< std::vector<const dunedaq::confmodel::Resource *> >& out,
58 : dunedaq::confmodel::TestCircularDependency& cd_fuse)
59 : {
60 0 : dunedaq::confmodel::AddTestOnCircularDependency add_fuse_test(cd_fuse, resource_set);
61 :
62 : // add the resource set to the path
63 0 : p_list.push_back(resource_set);
64 :
65 : // check if the application is in the resource relationship, i.e. is a resource or belongs to resource set(s)
66 0 : for (const auto& i : resource_set->contained_resources()) {
67 0 : if (i->config_object().implementation() == child) {
68 0 : out.push_back(p_list);
69 : }
70 0 : else if (const dunedaq::confmodel::ResourceSet * rs = i->cast<dunedaq::confmodel::ResourceSet>()) {
71 0 : make_parents_list(child, rs, p_list, out, cd_fuse);
72 : }
73 0 : }
74 :
75 : // remove the resource set from the path
76 0 : p_list.pop_back();
77 0 : }
78 :
79 : void
80 0 : make_parents_list(
81 : const dunedaq::conffwk::ConfigObjectImpl * child,
82 : const dunedaq::confmodel::Segment * segment,
83 : std::vector<const dunedaq::confmodel::Resource *> & p_list,
84 : std::list<std::vector<const dunedaq::confmodel::Resource *> >& out,
85 : bool is_segment,
86 : dunedaq::confmodel::TestCircularDependency& cd_fuse)
87 : {
88 0 : dunedaq::confmodel::AddTestOnCircularDependency add_fuse_test(cd_fuse, segment);
89 :
90 : // add the segment to the path
91 0 : p_list.push_back(segment);
92 :
93 : // check if the application is in the nested segment
94 0 : for (const auto& seg : segment->get_segments()) {
95 0 : if (seg->config_object().implementation() == child)
96 0 : out.push_back(p_list);
97 : else
98 0 : make_parents_list(child, seg, p_list, out, is_segment, cd_fuse);
99 : }
100 0 : if (!is_segment) {
101 0 : for (const auto& app : segment->get_applications()) {
102 0 : if (app->config_object().implementation() == child)
103 0 : out.push_back(p_list);
104 0 : else if (const auto resource_set = app->cast<dunedaq::confmodel::ResourceSet>())
105 0 : make_parents_list(child, resource_set, p_list, out, cd_fuse);
106 : }
107 : }
108 :
109 : // remove the segment from the path
110 :
111 0 : p_list.pop_back();
112 0 : }
113 :
114 :
115 : void
116 0 : check_segment(
117 : std::list< std::vector<const dunedaq::confmodel::Resource *> >& out,
118 : const dunedaq::confmodel::Segment * segment,
119 : const dunedaq::conffwk::ConfigObjectImpl * child,
120 : bool is_segment,
121 : dunedaq::confmodel::TestCircularDependency& cd_fuse)
122 : {
123 0 : dunedaq::confmodel::AddTestOnCircularDependency add_fuse_test(cd_fuse, segment);
124 :
125 0 : std::vector<const dunedaq::confmodel::Resource *> compList;
126 :
127 0 : if (segment->config_object().implementation() == child) {
128 0 : out.push_back(compList);
129 : }
130 0 : make_parents_list(child, segment, compList, out, is_segment, cd_fuse);
131 0 : }
132 : } // namespace
133 :
134 :
135 : namespace dunedaq::confmodel {
136 :
137 : void
138 0 : Resource::parents(
139 : const Session& session,
140 : std::list<std::vector<const Resource *>>& parents) const
141 : {
142 0 : const ConfigObjectImpl * obj_impl = config_object().implementation();
143 :
144 0 : const bool is_segment = castable(Segment::s_class_name);
145 :
146 0 : try {
147 0 : TestCircularDependency cd_fuse("component parents", &session);
148 :
149 : // check session's segment
150 0 : check_segment(parents, session.get_segment(), obj_impl, is_segment,
151 : cd_fuse);
152 :
153 :
154 0 : if (parents.empty()) {
155 0 : TLOG_DEBUG(1) << "cannot find segment/resource path(s) between Resource " << this << " and session " << &session << " objects (check this object is linked with the session as a segment or a resource)" ;
156 : }
157 : }
158 0 : catch (ers::Issue & ex) {
159 0 : ers::error(CannotGetParents(ERS_HERE, full_name(), ex));
160 0 : }
161 0 : }
162 :
163 : // ========================================================================
164 :
165 : std::vector<const Application*>
166 30 : Session::getSegmentApps(const Segment* segment,
167 : bool enabled_only) const {
168 30 : std::vector<const Application*> apps;
169 30 : auto segapps = segment->get_applications();
170 30 : if (enabled_only) {
171 0 : for (auto app : segapps) {
172 0 : auto comp = app->cast<Resource>();
173 0 : if (comp == nullptr || !comp->is_disabled(*this)) {
174 0 : apps.insert(apps.end(), app);
175 : }
176 : }
177 : }
178 : else {
179 30 : apps.swap(segapps);
180 : }
181 45 : for (auto seg : segment->get_segments()) {
182 15 : if (!enabled_only || !seg->is_disabled(*this)) {
183 15 : auto segapps = getSegmentApps(seg, enabled_only);
184 15 : apps.insert(apps.end(), segapps.begin(),segapps.end());
185 15 : }
186 : }
187 30 : return apps;
188 30 : }
189 :
190 : std::vector<const Application*>
191 15 : Session::all_applications() const {
192 15 : std::vector<const Application*> apps;
193 15 : auto segapps = getSegmentApps(get_segment(), false);
194 15 : apps.insert(apps.end(), segapps.begin(),segapps.end());
195 15 : return apps;
196 15 : }
197 :
198 : std::vector<const Application*>
199 0 : Session::enabled_applications() const {
200 0 : std::vector<const Application*> apps;
201 0 : auto segapps = getSegmentApps(get_segment(), true);
202 0 : apps.insert(apps.end(), segapps.begin(),segapps.end());
203 0 : return apps;
204 0 : }
205 :
206 :
207 : // ========================================================================
208 :
209 : std::set<const HostComponent*>
210 0 : DaqApplication::get_used_hostresources() const {
211 0 : std::set<const HostComponent*> res;
212 0 : for (auto module : get_modules()) {
213 0 : for (auto hostresource : module->get_used_resources()) {
214 0 : res.insert(hostresource);
215 : }
216 : }
217 0 : return res;
218 0 : }
219 :
220 : namespace {
221 0 : nlohmann::json get_json_config(conffwk::Configuration& confdb,
222 : const std::string& class_name,
223 : const std::string& uid,
224 : bool direct_only,
225 : bool skip_object_name) {
226 0 : using nlohmann::json;
227 0 : using namespace conffwk;
228 0 : TLOG_DBG(9) << "Getting attributes for " << uid << " of class " << class_name;
229 0 : json attributes;
230 0 : auto class_info = confdb.get_class_info(class_name);
231 0 : ConfigObject obj;
232 0 : confdb.get(class_name, uid, obj);
233 0 : for (auto attr : class_info.p_attributes) {
234 0 : if (attr.p_type == type_t::u8_type) {
235 0 : add_json_value<uint8_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
236 : }
237 : else if (attr.p_type == type_t::u16_type) {
238 0 : add_json_value<uint16_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
239 : }
240 : else if (attr.p_type == type_t::u32_type) {
241 0 : add_json_value<uint32_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
242 : }
243 : else if (attr.p_type == type_t::u64_type) {
244 0 : add_json_value<uint64_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
245 : }
246 : else if (attr.p_type == type_t::s8_type) {
247 0 : add_json_value<int8_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
248 : }
249 : else if (attr.p_type == type_t::s16_type) {
250 0 : add_json_value<int16_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
251 : }
252 : else if (attr.p_type == type_t::s32_type ||
253 : attr.p_type == type_t::s16_type) {
254 0 : add_json_value<int32_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
255 : }
256 : else if (attr.p_type == type_t::s64_type) {
257 0 : add_json_value<int64_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
258 : }
259 : else if (attr.p_type == type_t::float_type) {
260 0 : add_json_value<float>(obj, attr.p_name, attr.p_is_multi_value, attributes);
261 : }
262 : else if (attr.p_type == type_t::double_type) {
263 0 : add_json_value<double>(obj, attr.p_name, attr.p_is_multi_value, attributes);
264 : }
265 : else if (attr.p_type == type_t::bool_type) {
266 0 : add_json_value<bool>(obj, attr.p_name, attr.p_is_multi_value, attributes);
267 : }
268 : else if ((attr.p_type == type_t::string_type) ||
269 : (attr.p_type == type_t::enum_type) ||
270 : (attr.p_type == type_t::date_type) ||
271 : (attr.p_type == type_t::time_type)) {
272 0 : add_json_value<std::string>(obj, attr.p_name, attr.p_is_multi_value, attributes);
273 : }
274 0 : }
275 0 : if (!direct_only) {
276 0 : TLOG_DBG(9) << "Processing relationships";
277 0 : for (auto iter: class_info.p_relationships) {
278 0 : std::string rel_name = iter.p_name;
279 0 : if (iter.p_cardinality == cardinality_t::zero_or_one ||
280 : iter.p_cardinality == cardinality_t::only_one) {
281 0 : ConfigObject rel_obj;
282 0 : obj.get(rel_name, rel_obj);
283 0 : if (!rel_obj.is_null()) {
284 0 : TLOG_DBG(9) << "Getting attibute of relationship " << rel_name;
285 0 : attributes[rel_name] = get_json_config(confdb, rel_obj.class_name(),
286 : rel_obj.UID(),
287 : direct_only,
288 0 : skip_object_name);
289 : }
290 : else {
291 0 : TLOG_DBG(9) << "Relationship " << rel_name << " not set";
292 : }
293 0 : }
294 : else {
295 0 : TLOG_DBG(9) << "Relationship " << rel_name << " is multi value. "
296 0 : << "Getting attibutes for relationship.";
297 0 : std::vector<ConfigObject> rel_vec;
298 0 : obj.get(rel_name, rel_vec);
299 0 : std::vector<json> configs;
300 0 : for (auto rel_obj : rel_vec) {
301 0 : TLOG_DBG(9) << "Getting attibute of relationship " << rel_obj.UID();
302 0 : auto rel_conf = get_json_config(confdb, rel_obj.class_name(), rel_obj.UID(),
303 0 : direct_only, skip_object_name);
304 0 : configs.push_back(rel_conf);
305 0 : }
306 0 : attributes[rel_name] = configs;
307 0 : }
308 0 : }
309 : }
310 :
311 0 : if (skip_object_name) {
312 0 : return attributes;
313 : }
314 0 : json json_config;
315 0 : json_config[uid] = attributes;
316 0 : return json_config;
317 0 : }
318 : } // namespace
319 :
320 0 : nlohmann::json Jsonable::to_json(bool direct_only,
321 : bool skip_object_name) const {
322 0 : return get_json_config(p_registry.configuration(), class_name(), UID(), direct_only,
323 0 : skip_object_name);
324 : }
325 :
326 0 : const std::vector<std::string> DaqApplication::construct_commandline_parameters(
327 : const conffwk::Configuration& confdb,
328 : const dunedaq::confmodel::Session* session) const {
329 :
330 0 : return construct_commandline_parameters_appfwk<dunedaq::confmodel::DaqApplication>(this, confdb, session);
331 : }
332 :
333 0 : const std::vector<std::string> RCApplication::construct_commandline_parameters(
334 : const conffwk::Configuration& confdb,
335 : const dunedaq::confmodel::Session* session) const {
336 :
337 0 : const std::string configuration_uri = confdb.get_impl_spec();
338 0 : const dunedaq::confmodel::Service* control_service = nullptr;
339 :
340 0 : const std::string controller_log_level = session->get_controller_log_level();
341 :
342 0 : for (auto const *as : get_exposes_service()) {
343 0 : if (as->UID().ends_with("_control")) {
344 0 : if (control_service)
345 0 : throw DuplicatedControlService(ERS_HERE, as->UID());
346 : control_service = as;
347 : }
348 : }
349 :
350 0 : if (control_service == nullptr)
351 0 : throw NoControlServiceDefined(ERS_HERE, UID());
352 :
353 0 : const std::string control_uri =
354 0 : control_service->get_protocol()
355 0 : + "://"
356 0 : + get_runs_on()->get_runs_on()->UID()
357 0 : + ":"
358 0 : + std::to_string(control_service->get_port());
359 :
360 0 : std::vector<std::string> ret = { "-l", controller_log_level };
361 0 : ret.push_back(configuration_uri);
362 0 : ret.push_back(control_uri);
363 0 : ret.push_back(UID());
364 0 : ret.push_back(session->UID());
365 0 : return ret;
366 0 : }
367 :
368 :
369 :
370 : std::vector<const confmodel::DetectorStream*>
371 61 : DetectorToDaqConnection::streams() const {
372 61 : std::vector<const confmodel::DetectorStream*> all_streams;
373 : // Loop over senders
374 122 : for (auto sender : this->senders()) {
375 61 : auto sender_streams = sender->get_streams();
376 61 : all_streams.insert(all_streams.end(), sender_streams.begin(), sender_streams.end());
377 122 : }
378 61 : return all_streams;
379 0 : }
380 :
381 10 : std::string OpMonURI::get_URI( const std::string & /* app */) const {
382 :
383 10 : auto type = get_type();
384 10 : if ( type == "file" ) {
385 10 : return type + "://" + get_path();
386 : }
387 :
388 0 : if ( type == "stream" ) {
389 0 : return type + "://" + get_path();
390 : }
391 :
392 0 : return "stdout://";
393 10 : }
394 :
395 257 : bool Resource::is_disabled(const dunedaq::confmodel::ResourceTree& holder) const {
396 257 : return (!holder.disabled_components().is_enabled(this));
397 : }
398 47 : bool Resource::compute_disabled_state(const std::set<std::string>& disabled_resources) const {
399 47 : TLOG_DEBUG(6) << "No compute_disabled_state method defined for Resource " << class_name();
400 47 : if (disabled_resources.contains(UID())) {
401 : return true;
402 : }
403 : return false;
404 : }
405 :
406 32 : std::vector<const Resource*> DetDataSender::contained_resources() const {
407 32 : return to_resources(get_streams());
408 : }
409 :
410 9 : std::vector<const Resource*> DetectorToDaqConnection::contained_resources() const {
411 9 : auto res = to_resources(senders());
412 9 : res.push_back(receiver());
413 9 : return res;
414 0 : }
415 :
416 :
417 : bool
418 6 : DetectorToDaqConnection::compute_disabled_state(const std::set<std::string>& disabled_resources) const {
419 6 : if (disabled_resources.contains(UID())) {
420 : return true;
421 : }
422 6 : bool send_disabled = true;
423 14 : for (auto sender: senders()) {
424 11 : if (!sender->compute_disabled_state(disabled_resources)) {
425 3 : send_disabled = false;
426 3 : break;
427 : }
428 6 : }
429 6 : TLOG_DBG(6) << "receiver disabled=" << receiver()->compute_disabled_state(disabled_resources)
430 6 : << " senders disabled=" << send_disabled;
431 6 : if (receiver()->compute_disabled_state(disabled_resources) || send_disabled) {
432 : return true;
433 : }
434 : return false;
435 : }
436 :
437 : std::vector<const Resource*>
438 5 : Segment::contained_resources() const {
439 : // All our contained segments are resources
440 5 : std::vector<const Resource*> resources = to_resources(get_segments());
441 :
442 : // Only a subset of our applications might be resources so check individually
443 20 : for (auto app: get_applications()) {
444 15 : TLOG_DBG(6) << "Checking " << app->UID();
445 15 : auto res=app->cast<const Resource>();
446 15 : if (res != nullptr) {
447 15 : TLOG_DBG(6) << "Adding " << app->UID();
448 15 : resources.push_back(res);
449 : }
450 : }
451 5 : TLOG_DBG(6) << "Returning vector of " << resources.size() << " resources";
452 5 : return resources;
453 0 : }
454 :
455 : bool
456 2 : Segment::compute_disabled_state(const std::set<std::string>& disabled) const {
457 2 : if (disabled.contains(UID())) {
458 : return true;
459 : }
460 8 : for (auto app: get_applications()) {
461 6 : auto res=app->cast<const Resource>();
462 6 : if (res == nullptr) {
463 0 : return false;
464 : }
465 : }
466 6 : for (auto res: contained_resources()) {
467 5 : if (!res->compute_disabled_state(disabled)) {
468 1 : return false;
469 : }
470 2 : }
471 1 : return true;
472 : }
473 :
474 : } // namespace dunedaq::confmodel
|