Skip to content

Commit

Permalink
[irods#7256] Documentation, clang-tidy, and other tweaks for new API …
Browse files Browse the repository at this point in the history
…endpoint.
  • Loading branch information
korydraughn authored and alanking committed Sep 29, 2023
1 parent 9a4ca3c commit 1d34d9a
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 74 deletions.
72 changes: 46 additions & 26 deletions lib/api/include/irods/get_resource_info_for_operation.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#ifndef IRODS_GET_RESOURCE_INFO_FOR_OPERATION_H
#define IRODS_GET_RESOURCE_INFO_FOR_OPERATION_H

/// \file

#include "irods/dataObjInpOut.h"
Expand All @@ -9,56 +10,75 @@ struct RcComm;
#ifdef __cplusplus
extern "C" {
#endif

/// Get preferred-resource information for the specified operation.
///
/// \param[in] _comm An rcComm_t connection handle to the server.
/// \param[in] _comm An RcComm connection handle to the server.
/// \param[in] _dataObjInp \parblock A DataObjInp describing the data object operation.
/// - \p objPath: The logical path of the target data object.
/// - \p condInput: A list of options that influence the results of the operation.
/// - \p REPL_NUM_KW - The replica number of the copy to upload.
/// - \p GET_RESOURCE_INFO_FOR_OPERATION_KW - The operation of interest. The following values are supported:
/// - "CREATE"
/// - "WRITE"
/// - "OPEN"
/// - "UNLINK"
/// - \p RESC_NAME_KW - Resource name hint. Given the name of a root resource, influences voting to select the appropriate replica.
/// - \p RESC_HIER_STR_KW - Resource hierarchy hint. Given a hierarchy string, specifies the desired replica.
/// - \p GET_RESOURCE_INFO_FOR_OPERATION_KW: The operation of interest. This option is required. The following
/// values are supported:
/// - \p "CREATE"
/// - \p "WRITE"
/// - \p "OPEN"
/// - \p "UNLINK"
/// - \p RESC_NAME_KW: Resource name hint. Given the name of a root resource, influences voting to select the
/// appropriate replica.
/// - \p RESC_HIER_STR_KW: Resource hierarchy hint. Given a hierarchy string, specifies the desired replica.
/// - \p REPL_NUM_KW: Replica number hint. Given a replica number, specifies the desired replica.
/// \endparblock
/// \param[out] _out_info \parblock a JSON string with keys "host" and "resource_hierarchy", identifying target server and supplying a
/// resource hierarchy string denoting a specific data object replica for the logical path given as input.
/// \endparblock
///
/// \b Example _out_info:
/// \param[out] _out_info \parblock a JSON string with keys \p "host" and \p "resource_hierarchy", identifying target
/// server and supplying a resource hierarchy string denoting a specific data object replica for
/// the logical path given as input.
///
/// On success, \p _out_info will have the following structure:
/// \code{.js}
/// {
/// "host": <string>,
/// "resource_hierarchy": <string>
/// "host": string,
/// "resource_hierarchy": string
/// }
/// \endcode
/// \endparblock
///
/// \b Example usage:
///
/// \b Example
/// \code{.cpp}
/// RcComm* comm = // Our iRODS connection handle.
///
/// DataObjInp inp;
/// memset(&inp, 0, sizeof(DataObjInp));
///
/// // Set the full logical path to the data object of interest.
/// // The data object may or may not exist depending on what the client is
/// // attempting to do.
/// strncpy(inp.objPath, "/tempZone/home/rods/data_object", MAX_NAME_LEN);
/// char* char_buffer = 0;
/// addKeyVal(&input.condInput, "GET_RESOURCE_INFO_OP_TYPE_KW", "CREATE");
/// addKeyVal(&input.condInput, "RESC_NAME_KW", "my_root_resource");
/// const int ec = rc_get_resource_info_for_operation(&comm, &inp, &char_buffer);
/// if (ec < 0 || NULL == char_buffer) {
///
/// // Set the operation type for resource hierarchy resolution. This is required.
/// // This influences how voting is carried out.
/// addKeyVal(&inp.condInput, GET_RESOURCE_INFO_OP_TYPE_KW, "CREATE");
///
/// // A pointer that will point to a heap-allocated buffer holding the JSON
/// // string if the API call succeeds.
/// char* char_buffer = NULL;
///
/// const int ec = rc_get_resource_info_for_operation(comm, &inp, &char_buffer);
/// if (ec < 0) {
/// // Handle error.
/// }
/// // Here, we can parse and use the JSON-formatted _out_info parameter value contained in char_buffer.
///
/// // Here, we can parse and use the JSON-formatted string contained in char_buffer.
///
/// // Free the buffer when we're done.
/// free(char_buffer);
/// \endcode
///
/// \return integer
/// \retval 0 on success.
/// \return An integer.
/// \retval 0 On success.
/// \retval <0 On failure.
///
/// \since 4.3.1
int rc_get_resource_info_for_operation(struct RcComm* _comm, const struct DataObjInp* _dataObjInp, char** _out_info);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
73 changes: 54 additions & 19 deletions server/api/include/irods/rs_get_resource_info_for_operation.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#ifndef IRODS_RS_GET_RESOURCE_INFO_FOR_OPERATION_HPP
#define IRODS_RS_GET_RESOURCE_INFO_FOR_OPERATION_HPP

/// \file

#include "irods/dataObjInpOut.h"
Expand All @@ -8,36 +9,70 @@ struct RsComm;

/// Get preferred-resource information for the specified operation.
///
/// \param[in] _rsComm An rsComm_t connection handle to the server.
/// \param[in] _comm An RsComm connection handle to the server.
/// \param[in] _dataObjInp \parblock A DataObjInp describing the data object operation.
/// - \p objPath: The logical path of the target data object.
/// - \p condInput: A list of options that influence the results of the operation.
/// - \p REPL_NUM_KW - The replica number of the copy to upload.
/// - \p GET_RESOURCE_INFO_FOR_OPERATION_KW - The operation of interest. The following values are supported:
/// - "CREATE"
/// - "WRITE"
/// - "OPEN"
/// - "UNLINK"
/// - \p RESC_NAME_KW - Resource name hint. Given the name of a root resource, influences voting to select the appropriate replica.
/// - \p RESC_HIER_STR_KW - Resource hierarchy hint. Given a hierarchy string, specifies the desired replica.
/// \endparblock
/// \param[out] _out_info \parblock a JSON string with keys "host" and "resource_hierarchy", identifying target server and supplying a
/// resource hierarchy string denoting a specific data object replica for the logical path given as input.
/// - \p GET_RESOURCE_INFO_FOR_OPERATION_KW: The operation of interest. This option is required. The following
/// values are supported:
/// - \p "CREATE"
/// - \p "WRITE"
/// - \p "OPEN"
/// - \p "UNLINK"
/// - \p RESC_NAME_KW: Resource name hint. Given the name of a root resource, influences voting to select the
/// appropriate replica.
/// - \p RESC_HIER_STR_KW: Resource hierarchy hint. Given a hierarchy string, specifies the desired replica.
/// - \p REPL_NUM_KW: Replica number hint. Given a replica number, specifies the desired replica.
/// \endparblock
/// \param[out] _out_info \parblock a JSON string with keys \p "host" and \p "resource_hierarchy", identifying target
/// server and supplying a resource hierarchy string denoting a specific data object replica for
/// the logical path given as input.
///
/// \b Example _out_info:
///
/// On success, \p _out_info will have the following structure:
/// \code{.js}
/// {
/// "host": <string>,
/// "resource_hierarchy": <string>
/// "host": string,
/// "resource_hierarchy": string
/// }
/// \endcode
/// \endparblock
///
/// \b Example
/// \code{.cpp}
/// RsComm* comm = // Our iRODS connection handle.
///
/// DataObjInp inp;
/// memset(&inp, 0, sizeof(DataObjInp));
///
/// // Set the full logical path to the data object of interest.
/// // The data object may or may not exist depending on what the client is
/// // attempting to do.
/// strncpy(inp.objPath, "/tempZone/home/rods/data_object", MAX_NAME_LEN);
///
/// // Set the operation type for resource hierarchy resolution. This is required.
/// // This influences how voting is carried out.
/// addKeyVal(&inp.condInput, GET_RESOURCE_INFO_OP_TYPE_KW, "CREATE");
///
/// // A pointer that will point to a heap-allocated buffer holding the JSON
/// // string if the API call succeeds.
/// char* char_buffer = NULL;
///
/// const int ec = rs_get_resource_info_for_operation(comm, &inp, &char_buffer);
/// if (ec < 0) {
/// // Handle error.
/// }
///
/// // Here, we can parse and use the JSON-formatted string contained in char_buffer.
///
/// // Free the buffer when we're done.
/// free(char_buffer);
/// \endcode
///
/// \return integer
/// \retval 0 on success.
/// \return An integer.
/// \retval 0 On success.
/// \retval <0 On failure.
///
/// \since 4.3.1
int rs_get_resource_info_for_operation(RsComm* _rsComm, DataObjInp* _dataObjInp, char** _out_info);
int rs_get_resource_info_for_operation(RsComm* _comm, DataObjInp* _dataObjInp, char** _out_info);

#endif // IRODS_RS_GET_RESOURCE_INFO_FOR_OPERATION_HPP
61 changes: 32 additions & 29 deletions server/api/src/rs_get_resource_info_for_operation.cpp
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
#include "irods/get_resource_info_for_operation.h"
#include "irods/rs_get_resource_info_for_operation.hpp"

#include "irods/getRemoteZoneResc.h"
#include "irods/get_resource_info_for_operation.h"
#include "irods/irods_error.hpp"
#include "irods/irods_logger.hpp"
#include "irods/irods_resource_backport.hpp"
#include "irods/irods_resource_redirect.hpp"
#include "irods/rcMisc.h"
#include "irods/rodsConnect.h"
#include "irods/rodsError.h"
#include "irods/rodsErrorTable.h"

#include <nlohmann/json.hpp>
#include <fmt/format.h>
#include <nlohmann/json.hpp>

#include <algorithm>
#include <array>
#include <cstring> // for strdup
#include <string>

namespace
int rs_get_resource_info_for_operation(RsComm* _comm, DataObjInp* _dataObjInp, char** _out_info)
{
using log_api = irods::experimental::log::api;
} // anonymous namespace

int rs_get_resource_info_for_operation(rsComm_t* _rsComm, dataObjInp_t* _dataObjInp, char** _out_info)
{
using log_api = irods::experimental::log::api;
if (_rsComm == nullptr || _dataObjInp == nullptr || _out_info == nullptr) {
if (nullptr == _comm || nullptr == _dataObjInp || nullptr == _out_info) {
log_api::error("{}:{} Invalid input. Received one or more null pointers.", __func__, __LINE__);
return SYS_NULL_INPUT;
}

*_out_info = nullptr;

rodsServerHost_t* rodsServerHost = nullptr;
const int remoteFlag = getAndConnRemoteZone(_rsComm, _dataObjInp, &rodsServerHost, REMOTE_OPEN);
const int remoteFlag = getAndConnRemoteZone(_comm, _dataObjInp, &rodsServerHost, REMOTE_OPEN);
if (remoteFlag < 0) {
log_api::error("{}: getAndConnRemoteZone returned error: {}", __func__, remoteFlag);
log_api::error("{}: getAndConnRemoteZone returned error: [{}]", __func__, remoteFlag);
return remoteFlag;
}

Expand All @@ -37,54 +42,52 @@ int rs_get_resource_info_for_operation(rsComm_t* _rsComm, dataObjInp_t* _dataObj
}

const char* op_type = getValByKey(&_dataObjInp->condInput, GET_RESOURCE_INFO_OP_TYPE_KW);
if (op_type == nullptr) {
if (nullptr == op_type) {
constexpr auto ec = SYS_INVALID_INPUT_PARAM;
const auto message{
fmt::format("{}:{} GET_RESOURCE_INFO_OP_TYPE_KW must be set to a valid operation.", __func__, __LINE__)};
const auto message{fmt::format(
"{}: GET_RESOURCE_INFO_OP_TYPE_KW must be set to a valid operation. Received a null pointer.", __func__)};
log_api::error(message);
addRErrorMsg(&_rsComm->rError, ec, message.c_str());
addRErrorMsg(&_comm->rError, ec, message.c_str());
return ec;
}
const std::array allowed_ops{
irods::CREATE_OPERATION, irods::WRITE_OPERATION, irods::UNLINK_OPERATION, irods::OPEN_OPERATION};
irods::CREATE_OPERATION, irods::OPEN_OPERATION, irods::WRITE_OPERATION, irods::UNLINK_OPERATION};
// NOLINTNEXTLINE(readability-qualified-auto)
const auto found_operation = std::find(allowed_ops.begin(), allowed_ops.end(), op_type);
if (allowed_ops.end() == found_operation) {
constexpr auto ec = INVALID_OPERATION;
const auto message{
fmt::format("{}:{} GET_RESOURCE_INFO_OP_TYPE_KW must be set to a valid operation. Received instead: {}",
__func__,
__LINE__,
*found_operation)};
const auto message{fmt::format(
"{}: GET_RESOURCE_INFO_OP_TYPE_KW must be set to a valid operation. Received [{}].", __func__, op_type)};
log_api::error(message);
addRErrorMsg(&_rsComm->rError, ec, message.c_str());
addRErrorMsg(&_comm->rError, ec, message.c_str());
return ec;
}
std::string hier;
if (const char* hier_cstr = getValByKey(&_dataObjInp->condInput, RESC_HIER_STR_KW); hier_cstr == nullptr) {
if (const char* hier_cstr = getValByKey(&_dataObjInp->condInput, RESC_HIER_STR_KW); nullptr == hier_cstr) {
try {
auto result = irods::resolve_resource_hierarchy(*found_operation, _rsComm, *_dataObjInp);
auto result = irods::resolve_resource_hierarchy(*found_operation, _comm, *_dataObjInp);
hier = std::get<std::string>(result);
}
catch (const irods::exception& e) {
log_api::error(e.what());
return e.code();
log_api::error(e.client_display_what());
return static_cast<int>(e.code());
}
} // if keyword
}
else {
hier = hier_cstr;
}
std::string location;
// extract the host location from the resource hierarchy
irods::error ret = irods::get_loc_for_hier_string(hier, location);
if (!ret.ok()) {
auto error = PASSMSG(fmt::format("{} - failed in get_loc_for_hier_string", __func__), ret);
auto error = PASSMSG(fmt::format("{} - failed in get_loc_for_hier_string.", __func__), ret);
log_api::error(error.result());
return ret.code();
return static_cast<int>(ret.code());
}

nlohmann::json resc_info;
resc_info["host"] = location;
resc_info["resource_hierarchy"] = hier;
*_out_info = strdup(resc_info.dump().c_str());
return 0;
}
} // rs_get_resource_info_for_operation

0 comments on commit 1d34d9a

Please sign in to comment.