diff --git a/project/CMakeLists.txt b/project/CMakeLists.txt

index ed299d8..4db24b7 100644

--- a/project/CMakeLists.txt

+++ b/project/CMakeLists.txt

@@ -23,4 +23,9 @@ add_subdirectory(doct-cpp)

configure_file(

     ${CMAKE_SOURCE_DIR}/doct-cpp/res/demo_flow.json

     ${CMAKE_BINARY_DIR}/bin/demo_flow.json

+    COPYONLY)

+

+configure_file(

+    ${CMAKE_SOURCE_DIR}/doct-cpp/res/sysinfo_flow.json

+    ${CMAKE_BINARY_DIR}/bin/sysinfo_flow.json

     COPYONLY)

\ No newline at end of file

diff --git a/project/doct-cpp/CMakeLists.txt b/project/doct-cpp/CMakeLists.txt

index 9a33324..4097916 100644

--- a/project/doct-cpp/CMakeLists.txt

+++ b/project/doct-cpp/CMakeLists.txt

@@ -12,6 +12,8 @@ add_library(doct-cpp-lib

     src/data/collector_task.cpp

     src/data/tweaker_task.cpp

     src/data/flow.cpp

+    src/data/sysinfo_task.cpp

+    src/systeminfo_task_runner.cpp

)

target_link_libraries(doct-cpp-lib LINK_PUBLIC ext_tools)

target_include_directories(doct-cpp-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

diff --git a/project/doct-cpp/include/data/sysinfo_task.hpp b/project/doct-cpp/include/data/sysinfo_task.hpp

new file mode 100644

index 0000000..949ca1b

--- /dev/null

+++ b/project/doct-cpp/include/data/sysinfo_task.hpp

@@ -0,0 +1,26 @@

+// Copyright © doWhile 2020

+

+#ifndef DOCT_DATA_SYSINFO_TASK_H

+#define DOCT_DATA_SYSINFO_TASK_H

+

+#include "task.hpp"

+

+#include <nlohmann/json.hpp>

+

+#include <string>

+

+

+namespace doWhile::doct::data

+{

+

+struct SysInfoTask : public Task

+{

+    virtual ~SysInfoTask() = default;

+    virtual std::string str() const override;

+};

+

+void from_json(const nlohmann::json& json, SysInfoTask& sysInfoTask);

+

+}

+

+#endif // DOCT_DATA_SYSINFO_TASK_H

diff --git a/project/doct-cpp/include/systeminfo_task_runner.hpp b/project/doct-cpp/include/systeminfo_task_runner.hpp

new file mode 100644

index 0000000..020c0f8

--- /dev/null

+++ b/project/doct-cpp/include/systeminfo_task_runner.hpp

@@ -0,0 +1,37 @@

+// Copyright © doWhile 2020

+

+#ifndef DOCT_SYSINFO_TASK_RUNNER_H

+#define DOCT_SYSINFO_TASK_RUNNER_H

+

+#include "task_result.hpp"

+#include "sysinfo_task.hpp"

+#include "system_info.hpp"

+

+#include <string>

+

+namespace doWhile::doct

+{

+

+class SystemInfoTaskRunner

+{

+    public:

+        SystemInfoTaskRunner() = delete;

+

+        /**

+         * \brief Fetches and reports the system information for the given host

+         *

+         * \param task A SystemInfpTask to run

+         * \param collector The Collector to run the task on

+         * \return Results of running the task, format depends on task type

+         */

+        static TaskResult runTask(std::shared_ptr<data::SysInfoTask> task, ext_tools::SystemInfo* systemInfo);

+

+    private:

+

+        static std::string humanise(long input);

+        static std::string getHosname(ext_tools::SystemInfo* systemInfo);

+};

+

+}

+

+#endif // DOCT_SYSINFO_TASK_RUNNER_H

diff --git a/project/doct-cpp/res/sysinfo_flow.json b/project/doct-cpp/res/sysinfo_flow.json

new file mode 100644

index 0000000..e7cbb57

--- /dev/null

+++ b/project/doct-cpp/res/sysinfo_flow.json

@@ -0,0 +1,9 @@

+{

+       "hostname": "host.name",

+       "tasks": [

+              {

+                      "type": "SysInfoTask",

+                      "description": "Report sysinfo"

+              }

+       ]

+}

\ No newline at end of file

diff --git a/project/doct-cpp/src/data/flow.cpp b/project/doct-cpp/src/data/flow.cpp

index 15269dd..d895fb8 100644

--- a/project/doct-cpp/src/data/flow.cpp

+++ b/project/doct-cpp/src/data/flow.cpp

@@ -4,6 +4,7 @@

 

 #include "collector_task.hpp"

#include "tweaker_task.hpp"

+#include "sysinfo_task.hpp"

 

 #include <stdexcept>

 

@@ -32,6 +33,12 @@ void from_json(const nlohmann::json& json, Flow& flow)

             from_json(jsonTask, *task);

             flow.tasks.push_back(task);

         }

+        else if (jsonTask.at(TYPE) == "SysInfoTask")

+        {

+            auto task = std::make_shared<SysInfoTask>();

+            from_json(jsonTask, *task);

+            flow.tasks.push_back(task);

+        }

         else

        {

             throw std::invalid_argument("Error while parsing flow file, unknown task type: " + jsonTask.at(TYPE).get<std::string>());

diff --git a/project/doct-cpp/src/data/sysinfo_task.cpp b/project/doct-cpp/src/data/sysinfo_task.cpp

new file mode 100644

index 0000000..007b779

--- /dev/null

+++ b/project/doct-cpp/src/data/sysinfo_task.cpp

@@ -0,0 +1,18 @@

+// Copyright © doWhile 2020

+

+#include "sysinfo_task.hpp"

+

+namespace doWhile::doct::data

+{

+

+std::string SysInfoTask::str() const

+{

+    return "SystemInfoTask";

+}

+

+void from_json(const nlohmann::json& json, SysInfoTask& sysInfoTask)

+{

+    json.at("description").get_to(sysInfoTask.description);

+}

+

+}

\ No newline at end of file

diff --git a/project/doct-cpp/src/flow_runner.cpp b/project/doct-cpp/src/flow_runner.cpp

index 7c1976f..74a67c3 100644

--- a/project/doct-cpp/src/flow_runner.cpp

+++ b/project/doct-cpp/src/flow_runner.cpp

@@ -4,6 +4,9 @@

#include "collector_task_runner.hpp"

#include "tweaker_task_runner.hpp"

#include "tweaker.hpp"

+#include "system_info.hpp"

+#include "systeminfo_task_runner.hpp"

+#include "sysinfo_task.hpp"

 

 #include <nlohmann/json.hpp>

 

@@ -51,6 +54,11 @@ TaskResult FlowRunner::runTask(std::shared_ptr<data::Task>& task, const std::str

         ext_tools::Tweaker* tweaker = ext_tools::Tweaker::lookup(hostname);

         return TweakerTaskRunner::runTask(tweakerTask, tweaker);

     }

+    if (task != nullptr)

+    {

+        auto sysInfoTask = std::dynamic_pointer_cast<SysInfoTask>(task);

+        return SystemInfoTaskRunner::runTask(sysInfoTask, ext_tools::SystemInfo::get(hostname));

+    }

 

     throw std::invalid_argument("Unknown task type");

}

diff --git a/project/doct-cpp/src/systeminfo_task_runner.cpp b/project/doct-cpp/src/systeminfo_task_runner.cpp

new file mode 100644

index 0000000..6084a82

--- /dev/null

+++ b/project/doct-cpp/src/systeminfo_task_runner.cpp

@@ -0,0 +1,70 @@

+// Copyright © doWhile 2020

+

+#include "systeminfo_task_runner.hpp"

+#include "system_info.hpp"

+

+#include <string>

+#include <vector>

+#include <sstream>

+#include <algorithm>

+

+namespace doWhile::doct

+{

+

+TaskResult SystemInfoTaskRunner::runTask(std::shared_ptr<data::SysInfoTask> task, ext_tools::SystemInfo* systemInfo)

+{

+    TaskResult taskResult{task};

+    taskResult.setSuccess(true);

+

+    std::vector<std::string> tableRows;

+    tableRows.push_back("----------------------------------------");

+    tableRows.push_back("| Hostname: " + getHosname(systemInfo));

+    tableRows.push_back("| Cpus: " + std::to_string(systemInfo->getCpus().size()));

+    for(int i = 0; i < systemInfo->getCpus().size(); i++)

+    {

+        auto c = systemInfo->getCpus()[i];

+        tableRows.push_back("| - Cpu #" + std::to_string(i) + " core: " + std::to_string(c->getCore()));

+        tableRows.push_back("| - Cpu #" + std::to_string(i) + " utilisation: " + std::to_string(c->getCpuUtilization()));

+    }

+

+    auto cpus = systemInfo->getCpus();

+    std::vector<double> cpuUtilizations;

+    std::transform(cpus.begin(), cpus.end(), std::back_inserter(cpuUtilizations), [](std::shared_ptr<ext_tools::CpuCoreInfo> cpu) { return cpu->getCpuUtilization(); });

+    auto average = std::to_string(std::accumulate(cpuUtilizations.begin(), cpuUtilizations.end(), 0.0) / cpuUtilizations.size());

+

+    tableRows.push_back("| Avarege utilisation: " + average.substr(0,4));

+

+    auto memTotal = humanise(systemInfo->getTotalMemory() * 1000 * 1000 /* To bytes for humanisation */);

+    auto memUsedl = humanise(systemInfo->getMemoryUsage() * 1000 * 1000 /* To bytes for humanisation */);

+    tableRows.push_back("| Memory: " + memUsedl + " of " + memTotal);

+    tableRows.push_back("-------------------------------------");

+

+    for (const auto row : tableRows)

+        taskResult.addMessage(row);

+

+    return taskResult;

+}

+

+std::string SystemInfoTaskRunner::humanise(long input)

+{

+    std::vector<std::string> _orders { "B", "kB", "MB", "GB", "PB", "TB" };

+

+    int divisions = 0;

+    while (input > 1024)

+    {

+        input = input / 1024;

+        divisions = divisions + 1;

+    }

+

+    std::ostringstream stream;

+    stream << input << " " << _orders[divisions];

+

+    return stream.str();

+}

+

+std::string SystemInfoTaskRunner::getHosname(ext_tools::SystemInfo* systemInfo)

+{

+    return systemInfo->hostname;

+}

+

+}

\ No newline at end of file

diff --git a/project/ext_tools/include/system_info.hpp b/project/ext_tools/include/system_info.hpp

index ccd7dd9..0e3b7fe 100644

--- a/project/ext_tools/include/system_info.hpp

+++ b/project/ext_tools/include/system_info.hpp

@@ -11,10 +11,13 @@

#include <memory>

#include <map>

 

-namespace doWhile::doct::ext_tools

+namespace doWhile::doct

{

+    class SystemInfoTaskRunner;

+}

 

-//class CpuCoreInfo;

+namespace doWhile::doct::ext_tools

+{

 

 class SystemInfo

{

@@ -52,6 +55,9 @@ class SystemInfo

         SystemInfo(std::string hostname);

         std::string hostname;

         int targetMemoryUsage;

+

+        friend doWhile::doct::SystemInfoTaskRunner;

+

};

 

 }