diff --git a/CMakeLists.txt b/CMakeLists.txt index a500070..08f9b9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ set(REDFISH_HDR_PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/redfishPayload.h ${CMAKE_CURRENT_SOURCE_DIR}/include/redpath.h) -file(GLOB REDFISH_SRC src/*.c) +file(GLOB REDFISH_SRC src/*.c src/entities/*.c) source_group("Library Sources" FILES ${REDFISH_SRC}) diff --git a/examples/test.c b/examples/test.c index 1cf523c..4664f26 100644 --- a/examples/test.c +++ b/examples/test.c @@ -47,9 +47,28 @@ static struct option long_options[] = {"session", no_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"token", required_argument, 0, 'T'}, + {"command", required_argument, 0, 'c'}, {0, 0, 0, 0} }; +typedef void (*commandFunc)(redfishPayload* payload); + +typedef struct { + const char* commandName; + commandFunc function; +} commandMapping; + +static void getHealth(redfishPayload* payload); +static void getRollup(redfishPayload* payload); +static void getState(redfishPayload* payload); + +static commandMapping commands[] = { + {"getHealth", getHealth}, + {"getRollup", getRollup}, + {"getState", getState}, + {NULL, NULL} +}; + void inthand(int signum) { (void)signum; @@ -84,6 +103,7 @@ void print_usage(const char* name) printf(" -u, --username [user] The username to authenticate with\n"); printf(" -p, --password [pass] The password to authenticate with\n"); printf(" -S, --session Use session based auth, as opposed to basic auth\n"); + printf(" -c, --command [command] Run the specified command on the resource\n"); printf("\nQuery:\n"); printf(" Optional: /vXX - Where XX is the version to use. Defaults to v1.\n"); printf(" /Name - Where Name is the name of a JSON tag. If it contains an odata.id only\n"); @@ -182,6 +202,7 @@ typedef struct redfishService* redfish; int argc; char** argv; + commandMapping* command; } gotPayloadContext; void gotPayload(bool success, unsigned short httpCode, redfishPayload* payload, void* context) @@ -198,6 +219,13 @@ void gotPayload(bool success, unsigned short httpCode, redfishPayload* payload, } if(payload) { + if(myContext->command) + { + myContext->command->function(payload); + cleanupPayload(payload); + free(context); + return; + } switch(myContext->method) { case 0: @@ -254,6 +282,19 @@ void gotPayload(bool success, unsigned short httpCode, redfishPayload* payload, free(context); } +static commandMapping* getCommandByString(const char* name) +{ + size_t i; + for(i = 0; commands[i].commandName; i++) + { + if(strcasecmp(name, commands[i].commandName) == 0) + { + return &(commands[i]); + } + } + return NULL; +} + int main(int argc, char** argv) { int arg; @@ -271,10 +312,11 @@ int main(int argc, char** argv) char* token = NULL; enumeratorAuthentication auth; gotPayloadContext* context; + commandMapping* command = NULL; memset(&auth, 0, sizeof(auth)); - while((arg = getopt_long(argc, argv, "?VSH:M:f:W:u:p:vT:", long_options, &opt_index)) != -1) + while((arg = getopt_long(argc, argv, "?VSH:M:f:W:u:p:vT:c:", long_options, &opt_index)) != -1) { switch(arg) { @@ -340,6 +382,9 @@ int main(int argc, char** argv) case 'v': verbose++; break; + case 'c': + command = getCommandByString(optarg); + break; } } if(host == NULL) @@ -427,6 +472,7 @@ int main(int argc, char** argv) context->redfish = redfish; context->argc = argc; context->argv = argv; + context->command = command; if(query) { getPayloadByPathAsync(redfish, query, NULL, gotPayload, context); @@ -452,4 +498,113 @@ static void safeFree(void* ptr) } } +static void printHealth(redfishHealth health, const char* healthType) +{ + const char* healthStr; + switch(health) + { + case RedfishHealthError: + healthStr = "Error"; + break; + case RedfishHealthUnknown: + healthStr = "Unknown"; + break; + case RedfishHealthOK: + healthStr = "OK"; + break; + case RedfishHealthWarning: + healthStr = "Warning"; + break; + case RedfishHealthCritical: + healthStr = "Critical"; + break; + default: + healthStr = "Non-enum value"; + break; + } + printf("Resource %s is %s (%d)\n", healthType, healthStr, health); +} + +static void getHealth(redfishPayload* payload) +{ + redfishHealth health; + if(payload == NULL) + { + fprintf(stderr, "Payload is NULL!\n"); + return; + } + health = getResourceHealth(payload); + printHealth(health, "health"); +} + +static void getRollup(redfishPayload* payload) +{ + redfishHealth health; + if(payload == NULL) + { + fprintf(stderr, "Payload is NULL!\n"); + return; + } + health = getResourceRollupHealth(payload); + printHealth(health, "rollup health"); +} + +static void getState(redfishPayload* payload) +{ + redfishState state; + const char* stateStr; + if(payload == NULL) + { + fprintf(stderr, "Payload is NULL!\n"); + return; + } + state = getResourceState(payload); + switch(state) + { + case RedfishStateError: + stateStr = "Error"; + break; + case RedfishStateUnknown: + stateStr = "Unknown"; + break; + case RedfishStateEnabled: + stateStr = "Enabled"; + break; + case RedfishStateDisabled: + stateStr = "Disabled"; + break; + case RedfishStateStandbyOffline: + stateStr = "StandbyOffline"; + break; + case RedfishStateStandbySpare: + stateStr = "StandbySpare"; + break; + case RedfishStateInTest: + stateStr = "InTest"; + break; + case RedfishStateStarting: + stateStr = "Starting"; + break; + case RedfishStateAbsent: + stateStr = "Absent"; + break; + case RedfishStateUnavailableOffline: + stateStr = "UnavailableOffline"; + break; + case RedfishStateDeferring: + stateStr = "Deferring"; + break; + case RedfishStateQuiesced: + stateStr = "Quiesced"; + break; + case RedfishStateUpdating: + stateStr = "Updating"; + break; + default: + stateStr = "Non-enum value"; + break; + } + printf("Resource state is %s (%d)\n", stateStr, state); +} + /* vim: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/include/entities/resource.h b/include/entities/resource.h new file mode 100644 index 0000000..827c184 --- /dev/null +++ b/include/entities/resource.h @@ -0,0 +1,40 @@ +//---------------------------------------------------------------------------- +// Copyright Notice: +// Copyright 2017 Distributed Management Task Force, Inc. All rights reserved. +// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/blob/master/LICENSE.md +//---------------------------------------------------------------------------- +#ifndef _REDFISH_RESOURCE_H_ +#define _REDFISH_RESOURCE_H_ + +//redfishPayload is defined here... +#include "redfishPayload.h" + +typedef enum { + RedfishHealthError = -1, + RedfishHealthUnknown = 0, + RedfishHealthOK = 1, + RedfishHealthWarning = 2, + RedfishHealthCritical = 3 +} redfishHealth; + +typedef enum { + RedfishStateError = -1, + RedfishStateUnknown = 0, + RedfishStateEnabled = 1, + RedfishStateDisabled = 2, + RedfishStateStandbyOffline = 3, + RedfishStateStandbySpare = 4, + RedfishStateInTest = 5, + RedfishStateStarting = 6, + RedfishStateAbsent = 7, + RedfishStateUnavailableOffline = 8, + RedfishStateDeferring = 9, + RedfishStateQuiesced = 10, + RedfishStateUpdating = 11 +} redfishState; + +REDFISH_EXPORT redfishHealth getResourceHealth(redfishPayload* payload); +REDFISH_EXPORT redfishHealth getResourceRollupHealth(redfishPayload* payload); +REDFISH_EXPORT redfishState getResourceState(redfishPayload* payload); + +#endif diff --git a/include/redfish.h b/include/redfish.h index b605d4d..021d9b5 100644 --- a/include/redfish.h +++ b/include/redfish.h @@ -9,6 +9,7 @@ #include #include #include +#include /** * syslog style function used to debug libredfish. diff --git a/include/redfishPayload.h b/include/redfishPayload.h index f0d83da..7c2efdf 100644 --- a/include/redfishPayload.h +++ b/include/redfishPayload.h @@ -41,4 +41,6 @@ REDFISH_EXPORT bool getPayloadByNodeNameAsync(redfishPayload* payload REDFISH_EXPORT bool getPayloadByIndexAsync(redfishPayload* payload, size_t index, redfishAsyncOptions* options, redfishAsyncCallback callback, void* context); REDFISH_EXPORT bool getPayloadForPathAsync(redfishPayload* payload, redPathNode* redpath, redfishAsyncOptions* options, redfishAsyncCallback callback, void* context); +REDFISH_EXPORT redfishPayload* getPayloadByNodeNameNoNetwork(redfishPayload* payload, const char* nodeName); + #endif diff --git a/src/entities/resource.c b/src/entities/resource.c new file mode 100644 index 0000000..e394155 --- /dev/null +++ b/src/entities/resource.c @@ -0,0 +1,140 @@ +//---------------------------------------------------------------------------- +// Copyright Notice: +// Copyright 2018 Distributed Management Task Force, Inc. All rights reserved. +// License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libredfish/blob/master/LICENSE.md +//---------------------------------------------------------------------------- +#include + +#include "entities/resource.h" +#include "redfishPayload.h" +#include "../debug.h" + +#ifdef _MSC_VER +#define strcasecmp _stricmp +#endif + +static redfishHealth _getResourceHealth(redfishPayload* payload, const char* subElement, const char* function); + +redfishHealth getResourceHealth(redfishPayload* payload) +{ + return _getResourceHealth(payload, "Health", __FUNCTION__); +} + +redfishHealth getResourceRollupHealth(redfishPayload* payload) +{ + return _getResourceHealth(payload, "HealthRollup", __FUNCTION__); +} + +typedef struct { + const char* string; + redfishState state; +} stringToStateMap; + +static stringToStateMap stateMapping[] = { + {"Enabled", RedfishStateEnabled}, + {"Disabled", RedfishStateDisabled}, + {"StandbyOffline", RedfishStateStandbyOffline}, + {"StandbySpare", RedfishStateStandbySpare}, + {"InTest", RedfishStateInTest}, + {"Starting", RedfishStateStarting}, + {"Absent", RedfishStateAbsent}, + {"UnavailableOffline", RedfishStateUnavailableOffline}, + {"Deferring", RedfishStateDeferring}, + {"Quiesced", RedfishStateQuiesced}, + {"Updating", RedfishStateUpdating}, + {NULL, RedfishStateUnknown} +}; + +redfishState getResourceState(redfishPayload* payload) +{ + redfishPayload* status; + redfishPayload* state; + char* stateStr; + size_t i; + + if(payload == NULL) + { + REDFISH_DEBUG_WARNING_PRINT("%s: Payload is NULL\n", __FUNCTION__); + return RedfishStateError; + } + status = getPayloadByNodeNameNoNetwork(payload, "Status"); + if(status == NULL) + { + REDFISH_DEBUG_WARNING_PRINT("%s: Unable to obtain Status resource from payload...\n", __FUNCTION__); + return RedfishStateError; + } + state = getPayloadByNodeNameNoNetwork(status, "State"); + cleanupPayload(status); + if(state == NULL) + { + REDFISH_DEBUG_WARNING_PRINT("%s: Unable to obtain State resource from payload...\n", __FUNCTION__); + return RedfishStateError; + } + stateStr = getPayloadStringValue(state); + cleanupPayload(state); + if(stateStr == NULL) + { + return RedfishStateUnknown; + } + for(i = 0; stateMapping[i].string != NULL; i++) + { + if(strcasecmp(stateStr, stateMapping[i].string) == 0) + { + free(stateStr); + return stateMapping[i].state; + } + } + REDFISH_DEBUG_WARNING_PRINT("%s: Got unknown state string %s...\n", __FUNCTION__, stateStr); + free(stateStr); + return RedfishStateUnknown; +} + +static redfishHealth _getResourceHealth(redfishPayload* payload, const char* subElement, const char* function) +{ + redfishPayload* status; + redfishPayload* health; + char* healthStr; + + if(payload == NULL) + { + REDFISH_DEBUG_WARNING_PRINT("%s: Payload is NULL\n", function); + return RedfishHealthError; + } + status = getPayloadByNodeNameNoNetwork(payload, "Status"); + if(status == NULL) + { + REDFISH_DEBUG_WARNING_PRINT("%s: Unable to obtain Status resource from payload...\n", function); + return RedfishHealthError; + } + health = getPayloadByNodeNameNoNetwork(status, subElement); + cleanupPayload(status); + if(health == NULL) + { + REDFISH_DEBUG_WARNING_PRINT("%s: Unable to obtain %s resource from payload...\n", function, subElement); + return RedfishHealthError; + } + healthStr = getPayloadStringValue(health); + cleanupPayload(health); + if(healthStr == NULL) + { + return RedfishHealthUnknown; + } + if(strcasecmp(healthStr, "OK") == 0) + { + free(healthStr); + return RedfishHealthOK; + } + if(strcasecmp(healthStr, "Warning") == 0) + { + free(healthStr); + return RedfishHealthWarning; + } + if(strcasecmp(healthStr, "Critical") == 0) + { + free(healthStr); + return RedfishHealthCritical; + } + REDFISH_DEBUG_WARNING_PRINT("%s: Got unknown health string %s...\n", function, healthStr); + free(healthStr); + return RedfishHealthUnknown; +} diff --git a/src/payload.c b/src/payload.c index 3a1982e..73a18bd 100644 --- a/src/payload.c +++ b/src/payload.c @@ -203,6 +203,32 @@ redfishPayload* getPayloadByNodeName(redfishPayload* payload, const char* nodeNa return createRedfishPayload(value, payload->service); } +redfishPayload* getPayloadByNodeNameNoNetwork(redfishPayload* payload, const char* nodeName) +{ + json_t* value; + json_t* odataId; + + if(!payload || !nodeName) + { + return NULL; + } + + value = json_object_get(payload->json, nodeName); + if(value == NULL) + { + return NULL; + } + json_incref(value); + if(json_is_string(value)) + { + odataId = json_object(); + json_object_set(odataId, nodeName, value); + json_decref(value); + value = odataId; + } + return createRedfishPayload(value, payload->service); +} + redfishPayload* getPayloadByIndex(redfishPayload* payload, size_t index) { json_t* value = NULL;