guruprathapy

Adding DASH to C++ application

Blog Post created by guruprathapy Employee on Jul 22, 2020

DASH CLI supports new options to enable developers to send request query in JSON format to DASH systems and get the output in JSON format. The output can be interpreted by any programming language supporting JSON format. The output JSON is modeled like Redfish Schema published by DMTF.

 

In typical usage, DASH CLI is launched with request JSON, DASH CLI processes the request and forms the response in JSON format. This response is sent back to the launching application.

 

JSON is supported by almost all modern programming languages. Hence it will be easier to add DASH capability into any application or tool with few simple steps. Since the application will be launching DASH CLI, the integration with the application is therefore ‘loosely coupled’. DASH communication, DASH standards compliance, DASH security & stability are encapsulated within DASH CLI. The calling application does not require to know anything about DASH standard.

 

There are two new options in DASH CLI:

  • jdo option: With this flag, DASH request input is taken from command-line and output DASH response is written to console.
  • ji/jo option: With this flag, DASH request input is taken from file and output DASH response is written to a file.

jdo option is faster since it does not involve in any file operation.

 

Before starting

  • Download and install DASH CLI 3.0 version. In this blog, DASH CLI is installed in default path, “C:\Program Files (x86)\DASH CLI 3.0\”
  • Examples are illustrated with Visual Studio 2017. But any other IDE or editor can be used.
  • Refer DASH CLI Developer Guide, which is available in DASH CLI installation folder: “C:\Program Files (x86)\DASH CLI 3.0\docs\”, for JSON request & response formats for supported DASH profiles.
  • This blog provides the steps for C++ language sample code for using -jdo, -ji & -jo options.

 

JDO Flag usage

Using via direct command line

     dashcli -jdo

When this command is run, DASH CLI waits for input in JSON format. Once the input is provided, it will be executed by DASH CLI and output of which is written back in JSON format, as shown in the screenshot below.

Using JDO programmatically

Create a sample C++ Console application by following the steps below:

 

Step 1: Create a new project in Visual Studio by selecting from the Menu “File” > “New” > “Project”

   

Step 2: Select “Visual C++” -> “Console App”. Name the application “JDOApp” and click “OK” button.

 

 

Step 3: Add the two constant variables in main function which contains path to DASHCLI and arguments to it

      const char szArgs[] = (" -jdo ");

      const char szAppPath[] = ("C:\\Program Files (x86)\\DASH CLI 3.0\\bin\\dashcli.exe");

 

Step 4: Include windows, fstream and iostream header files as these will be referenced in the upcoming code.

 

#include <windows.h>

#include <fstream>

#include <iostream>

 

Step 5: Define the below functions

  • RunDashCLIWithJDO – This function takes 3 arguments Path to DASHCLI application, arguments and commands for DASHCLI. This function creates pipes, process to execute the DASHCLI with provided arguments and commands.
  • ReadFromDashCLIProcess – This function reads the output of DASHCLI process and prints to parent stdout.

 

int RunDashCLIWithJDO(const char szAppPath[], const char szArgs[], const char szCommands[])

{

      int iRetVal = 0;

 

      // Create PIPE for sending commands and reading output from DASHCLI process.

      SECURITY_ATTRIBUTES seAttr;

      // Set the bInheritHandle flag true so pipe handles are inherited.

      seAttr.nLength = sizeof(SECURITY_ATTRIBUTES);

      seAttr.bInheritHandle = true;

      seAttr.lpSecurityDescriptor = NULL;

 

      // Create a pipe for the DASHCli process's STDOUT.

      if (!CreatePipe(&ghDashCmdOUTRd, &ghDashCmdOUTWr, &seAttr, 0))

      {

            cout << "Stdout CreatePipe failed." << endl;

            iRetVal = -1;

      }

 

      // Ensure the read handle to the pipe for STDOUT is not inherited.

      if (!SetHandleInformation(ghDashCmdOUTRd, HANDLE_FLAG_INHERIT, 0))

      {

            cout << "Stdout SetHandleInformation failed." << endl;

            iRetVal = -1;

      }

 

      // Create a pipe for the DASHCli process's STDIN.

      if (!CreatePipe(&ghDashCmdINRd, &ghDashCmdINWr, &seAttr, 0))

      {

            cout << "Stdin CreatePipe failed." << endl;

            iRetVal = -1;

      }

 

      // Ensure the write handle to the pipe for STDIN is not inherited.

      if (!SetHandleInformation(ghDashCmdINWr, HANDLE_FLAG_INHERIT, 0))

      {

            cout << "Stdin SetHandleInformation failed." << endl;

            iRetVal = -1;

      }

 

      PROCESS_INFORMATION piProcInfo;

      STARTUPINFOA siStartInfo;

 

      // Set up members of the PROCESS_INFORMATION structure.

      ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

 

      // Set up members of the STARTUPINFO structure.

      // This structure specifies the STDIN and STDOUT handles for redirection.

      ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));

      siStartInfo.cb = sizeof(STARTUPINFO);

      siStartInfo.hStdError = ghDashCmdOUTWr;

      siStartInfo.hStdOutput = ghDashCmdOUTWr;

      siStartInfo.hStdInput = ghDashCmdINRd;

      siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

 

      // Create process with application path of DASHCLI and required arguments list.

      // If an error occurs, return -1

      if (iRetVal != 0 || !CreateProcessA(szAppPath, const_cast<LPSTR>(szArgs), NULL, NULL, true, 0, NULL, NULL, &siStartInfo, &piProcInfo))

      {

            std::cout << "Process/Pipe creation failed to execute DashCLI" << std::endl;

            iRetVal = -1;

      }

      else

      {

            // Sending commands to DashCLI

            std::cout << szCommands;

            unsigned long  dwRead = strlen(szCommands), dwWritten;

            WriteFile(ghDashCmdINWr, szCommands, dwRead, &dwWritten, NULL);

 

            // Wait for the process to complete execution.

            WaitForSingleObject(piProcInfo.hProcess, INFINITE);

 

            CloseHandle(piProcInfo.hProcess);

            CloseHandle(piProcInfo.hThread);

      }

 

      return iRetVal;

 

void ReadFromDashCLIProcess(void)

{

      unsigned long  dwRead, dwWritten;

      char chBuf[BUFSIZE];

      bool bSuccess = false;

      void * hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

 

      bSuccess = ReadFile(ghDashCmdOUTRd, chBuf, BUFSIZE, &dwRead, NULL);

 

      if (bSuccess && dwRead > 0)

      {

            WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);

      }

}

 

Step 6: Call “RunDashCLIWithJDO” and “ReadFromDashCLIProcess” function in “main” function by reading input from input_json.txt file.

 

char szCommands[BUFSIZE];

 

      // Read input commands to DashCLI from json file

      std::ifstream infile;

      infile.open("input_json.txt");

      infile >> szCommands;

      strcat_s(szCommands, "\r\n");      // Append carriage return and new line characters to input.

 

      cout << "Running DashCLI with JDO" << endl;

      if (0 == RunDashCLIWithJDO(szAppPath, szArgs, szCommands))

      {

            ReadFromDashCLIProcess();

      } 

 

The entire code at this stage should look like as below:

 

#include <windows.h>

#include <fstream>

#include <iostream>

 

using namespace std;

 

#define BUFSIZE 4096

 

void * ghDashCmdINRd = NULL;

void * ghDashCmdINWr = NULL;

void * ghDashCmdOUTRd = NULL;

void * ghDashCmdOUTWr = NULL;

 

// Create a child process to run DashCLI and redirect STDIN/STDOUT through pipes.

// Returns: -1 if process creation is failed.

//       0 if process creation is successful.

int RunDashCLIWithJDO(const char szAppPath[], const char szArgs[], const char szCommands[])

{

      int iRetVal = 0;

 

      // Create PIPE for sending commands and reading output from DASHCLI process.

      SECURITY_ATTRIBUTES seAttr;

      // Set the bInheritHandle flag true so pipe handles are inherited.

      seAttr.nLength = sizeof(SECURITY_ATTRIBUTES);

      seAttr.bInheritHandle = true;

      seAttr.lpSecurityDescriptor = NULL;

 

      // Create a pipe for the DASHCli process's STDOUT.

      if (!CreatePipe(&ghDashCmdOUTRd, &ghDashCmdOUTWr, &seAttr, 0))

      {

            cout << "Stdout CreatePipe failed." << endl;

            iRetVal = -1;

      }

 

      // Ensure the read handle to the pipe for STDOUT is not inherited.

      if (!SetHandleInformation(ghDashCmdOUTRd, HANDLE_FLAG_INHERIT, 0))

      {

            cout << "Stdout SetHandleInformation failed." << endl;

            iRetVal = -1;

      }

 

      // Create a pipe for the DASHCli process's STDIN.

      if (!CreatePipe(&ghDashCmdINRd, &ghDashCmdINWr, &seAttr, 0))

      {

            cout << "Stdin CreatePipe failed." << endl;

            iRetVal = -1;

      }

 

      // Ensure the write handle to the pipe for STDIN is not inherited.

      if (!SetHandleInformation(ghDashCmdINWr, HANDLE_FLAG_INHERIT, 0))

      {

            cout << "Stdin SetHandleInformation failed." << endl;

            iRetVal = -1;

      }

 

      PROCESS_INFORMATION piProcInfo;

      STARTUPINFOA siStartInfo;

 

      // Set up members of the PROCESS_INFORMATION structure.

      ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

 

      // Set up members of the STARTUPINFO structure.

      // This structure specifies the STDIN and STDOUT handles for redirection.

      ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));

      siStartInfo.cb = sizeof(STARTUPINFO);

      siStartInfo.hStdError = ghDashCmdOUTWr;

      siStartInfo.hStdOutput = ghDashCmdOUTWr;

      siStartInfo.hStdInput = ghDashCmdINRd;

      siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

 

      // Create process with application path of DASHCLI and required arguments list.

      // If an error occurs, return -1

      if (iRetVal != 0 || !CreateProcessA(szAppPath, const_cast<LPSTR>(szArgs), NULL, NULL, true, 0, NULL, NULL, &siStartInfo, &piProcInfo))

      {

            std::cout << "Process/Pipe creation failed to execute DashCLI" << std::endl;

            iRetVal = -1;

      }

      else

      {

            // Sending commands to DashCLI

            std::cout << szCommands;

            unsigned long  dwRead = strlen(szCommands), dwWritten;

            WriteFile(ghDashCmdINWr, szCommands, dwRead, &dwWritten, NULL);

 

            // Wait for the process to complete execution.

            WaitForSingleObject(piProcInfo.hProcess, INFINITE);

 

            CloseHandle(piProcInfo.hProcess);

            CloseHandle(piProcInfo.hThread);

      }

 

      return iRetVal;

}

 

// Read output from the DashCLI process

// and write to the parent STDOUT.

void ReadFromDashCLIProcess(void)

{

      unsigned long  dwRead, dwWritten;

      char chBuf[BUFSIZE];

      bool bSuccess = false;

      void * hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

 

      bSuccess = ReadFile(ghDashCmdOUTRd, chBuf, BUFSIZE, &dwRead, NULL);

 

      if (bSuccess && dwRead > 0)

      {

            WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);

      }

}

 

int main(int argc, char* argv[])

{

      const char szArgs[] = (" -jdo ");

 

      // Path to DashCLI application.

      const char szAppPath[] = ("C:\\Program Files (x86)\\DASH CLI 3.0\\bin\\dashcli.exe");

 

      char szCommands[BUFSIZE];

 

      // Read input commands to DashCLI from json file

      std::ifstream infile;

      infile.open("input_json.txt");

      infile >> szCommands;

      strcat_s(szCommands, "\r\n");      // Append carriage return and new line characters to input.

 

      cout << "Running DashCLI with JDO" << endl;

      if (0 == RunDashCLIWithJDO(szAppPath, szArgs, szCommands))

      {

            ReadFromDashCLIProcess();

      }

      cout << "DashCLI execution with JDO is complete." << endl;

 

      return 0;

} 

Step 7: In step 6, main function reads input for JDO from a JSON File (input_json.txt). It assumes that input_json.txt is present in the working directory of the project if the application is running through Visual Studio or it should be present in the exe application path.

 

Step 8: Contents of JSON text file can be any of the input from Developer guide like a discover command as shown below.

 

     {"h":"HP705G1","u":"adminUserName","P":"adminPassword","Commands":["discover"]}

 

Step 9: Run the JDOApp.exe application from the console.

 

 

Other Commands:

Discover Info through DashCLI JDO

This is to discover the given host and get the list of security profiles supported by the dash target system.

Update the input_json.txt with discover and info commands as below

   {"h":"HP705G1","u":"adminUserName","P":"adminPassword","Commands":["discover","info"]}

Repeat Step 9. Output will contain the discovery information under info tag and security profiles under SecurityProfile tag.

 

Power Status through DashCLI JDO

This is to get the current power status of a dash target system.

Update the input_json.txt with power status commands as below

{"h":"HP705G1","u":"adminUserName","t":"computersystem[0]","P":"adminPassword","Commands":["power","status"]}

Output will contain the current power status of the dash system. Power status will be in shown in the PowerState tag.

 

Change Power Status through DashCLI JDO

This is to change the power status of a dash target system.

Update the input_json.txt with power and available state commands as below

   {"h":"HP705G1","u":"adminUserName","P":"adminPassword","Commands":["power","sleep"]}

Output will contain the power change status of the dash system. ErrorCode tag will contain the status of the power operation 0 if power operation is successful. ErrorMessage will contain more information on the status of the operation as shown below

 

Ji JO Flag usage

Using via direct command line

     dashcli -ji input_json.txt -jo output_json.txt

Here, the file ‘input_json.txt’ has the DASH command in JSON format. DASH CLI executes this command and writes the output in JSON format to file specified by -jo option, which is output_json.txt. Usage is shown in the screenshot below.

Using JI/JO programmatically

Create a sample C++ console application by following the steps below:

 

Step 1: Create a new project in Visual Studio by selecting from the Menu “File” > “New” > “Project”

 

Step 2: Select “Visual C++” -> “Console App”. Name the application “JiJoApp” and click “OK” button.

 

 

Step 3: Add the two constant members which stores DashCLI application path  and DashCLI arguments in main function.

      const char szArgs[] = (" -ji input_json.txt -jo output_json.txt");

      const char szAppPath[] = ("C:\\Program Files (x86)\\DASH CLI 3.0\\bin\\dashcli.exe"); 

 

Step 4: Include required header files like windows.h and iostream

 

#include <windows.h>

#include <iostream>

 

Step 5: Define a function “RunDashCLIWithJiJO” which creates a process and executes DASHCLI application with JIJO parameters as shown below:

 

void RunDashCLIWithJiJO(const char szAppPath[], const char szArgs[])

{

      PROCESS_INFORMATION piProcInfo;

      STARTUPINFOA siStartInfo;

 

      // Set up members of the PROCESS_INFORMATION structure.

      ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

 

      // Set up members of the STARTUPINFO structure.

      ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));

      siStartInfo.cb = sizeof(STARTUPINFO);

 

      // Create process with application path of DASHCLI and required arguments list.

      if (!CreateProcessA(szAppPath, (LPSTR)szArgs, NULL, NULL, true, 0, NULL, NULL, &siStartInfo, &piProcInfo))

      {

            cout << "Process creation failed to execute DashCLI" << std::endl;

      }

      else

      {

            // Wait for the process to complete execution.

            WaitForSingleObject(piProcInfo.hProcess, INFINITE);

 

            CloseHandle(piProcInfo.hProcess);

            CloseHandle(piProcInfo.hThread);

            cout << "DashCLI execution complete." << endl;

      }

}

 

Step 6: Call “RunDashCLIWithJiJO” function in the “main” function

            RunDashCLIWithJiJO(szAppPath, szArgs);

 

The entire code at this stage should look like so:

 

#include <windows.h>

#include <iostream>

 

using namespace std;

 

// Create a child process to run DashCLI and redirect STDIN/STDOUT through pipes.

void RunDashCLIWithJiJO(const char szAppPath[], const char szArgs[])

{

      PROCESS_INFORMATION piProcInfo;

      STARTUPINFOA siStartInfo;

 

      // Set up members of the PROCESS_INFORMATION structure.

      ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

 

      // Set up members of the STARTUPINFO structure.

      ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));

      siStartInfo.cb = sizeof(STARTUPINFO);

 

      // Create process with application path of DASHCLI and required arguments list.

      if (!CreateProcessA(szAppPath, (LPSTR)szArgs, NULL, NULL, true, 0, NULL, NULL, &siStartInfo, &piProcInfo))

      {

            cout << "Process creation failed to execute DashCLI" << std::endl;

      }

      else

      {

            // Wait for the process to complete execution.

            WaitForSingleObject(piProcInfo.hProcess, INFINITE);

 

            CloseHandle(piProcInfo.hProcess);

            CloseHandle(piProcInfo.hThread);

            cout << "DashCLI execution complete." << endl;

      }

}

 

int main(int argc, char* argv[])

{

      const char szArgs[] = (" -ji input_json.txt -jo output_json.txt");

 

      // Path to DashCLI application.

      const char szAppPath[] = ("C:\\Program Files (x86)\\DASH CLI 3.0\\bin\\dashcli.exe");

 

      cout << "Running DashCLI with JIJO" << endl;

      RunDashCLIWithJiJO(szAppPath, szArgs);

 

      return 0;

} 

 

Step 7: In step 6, to call function “RunDashCLIWithJiJO”, DASHCLI argument expects the input JSON file which is input_json.txt to be present in the working directory if the sample application is running from Visual Studio or to be present in the exe path if the application is running from the command line.

 

Step 8: Put the following JSON test in input_json.txt file:

 

{"h":"HP705G1","u":"AdminUserName","P":"AdminPassword","Commands":["discover"]}

 

Step 9: Run the “JiJoApp.exe” application from the console.

 

Step 10: Check the content of the “output_json.txt” file using “type” command on the console as shown in the above command. Output_json.txt file will contain the output of DASHCLI for the commands in input_json.txt.

 

Other Commands:

Discover Info through DashCLI JiJO

This is to discover the given host and get the list of security profiles supported by the dash target system.

Update the input_json.txt with discover and info commands as below

{"h":"HP705G1","u":"adminUserName","P":"adminPassword","Commands":["discover","info"]}

Repeat Step 9 & 10. Output will be stored in json format in output_json.txt. This contains the discovery information under info tag and security profiles under SecurityProfile tag as show in the below snapshot.

 

Power Status through DashCLI JiJO

This is to get the current power status of a dash target system.

Update the input_json.txt with power status commands as below

{"h":"HP705G1","u":"adminUserName","P":"adminPassword","t":"computersystem[0]","Commands":["power","status"]}

Repeat above steps 9 & 10, output will be stored in the output_json.txt which contains the current power status of the dash system. Power status will be in shown in the PowerState tag.

 

Change Power Status through DashCLI JDO

This is to change the power status of a dash target system.

Update the input_json.txt with power and available state commands as below

{"h":"HP705G1","u":"adminUserName","P":"adminPassword","Commands":["power","sleep"]}

Output will contain the power change status of the dash system. ErrorCode tag will contain the status of the power operation 0 if power operation is successful. ErrorMessage will contain more information on the status of the operation as shown below

 

In this blog, DASH Discovery is illustrated. Similarly, other DASH profiles can be accessed by the application by framing the required JSON request. See the ‘DASH CLI Developer Guide’ for JSON format for other supported DASH profiles.

 

Attachments:

  • JDOApp solution
  • JiJoApp solution

 

For any further query, drop a note below or contact via mail dashsupport@amd.com

 

Reference:

  • DASH CLI Developer Guide (Available in DASH CLI installation folder: “C:\Program Files (x86)\DASH CLI 3.0\docs\”)

 

Useful links:

 

Related Blogs:

Attachments

Outcomes