Skip to content

Commit

Permalink
Make schemas selectable
Browse files Browse the repository at this point in the history
Which schemas are installed should be selectable in both a meson config,
and trivially by forks.  This commit gets us closer to that idea.

It does it in several ways, first, the code for generating
JsonSchemaFile resources has been changed to be generated at runtime,
based on files on disk.  This is slightly slower, but allows installing
schemas from anywhere, and matches the CSDL handling.

Next, the schema folders are separated into two sets
csdl -> This includes the complete schema pack from dmtf
installed -> this includes only the schemas the bmc includes

Similar folders exist for json-schema and json-schema-installed.

This allows any additional schemas to be a single symlink addition.
Note, this also checks in all of the dmtf json schemas, not just the
versions we use.  This allows us to update the schema pack without
needing to break our versions we ship.

Because the static files are now selectable, all files need to be in a
folder.  This forces the css and image for the redfish built-in gui to
be moved.

Tested:
/redfish/v1/JsonSchemas returns the correct result
/redfish/v1/JsonSchemas/UpdateService returns a JsonSchemaFile instance
/redfish/v1/JsonSchemas/UpdateService/UpdateService<version>json returns
the JsonSchemaFile contents.

Redfish service validator passes.

Change-Id: Ie96b2e4b623788dc2ec94eb40fcfd80325f0d826
Signed-off-by: Ed Tanous <ed@tanous.net>
  • Loading branch information
edtanous committed Jul 12, 2024
1 parent 3281bcf commit a529a6a
Show file tree
Hide file tree
Showing 351 changed files with 298 additions and 235 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
redfish-core/schema/dmtf
4 changes: 2 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,10 @@ summary(
section: 'Directories',
)

install_subdir('static', install_dir: 'share/www', strip_directory: true, follow_symlinks: true)
subdir('static')
subdir('redfish-core')

# Config subdirectory

subdir('config')
bmcweb_dependencies += conf_h_dep

Expand Down
143 changes: 110 additions & 33 deletions redfish-core/lib/redfish_v1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "http_response.hpp"
#include "query.hpp"
#include "registries/privilege_registry.hpp"
#include "schemas.hpp"
#include "utility.hpp"

#include <boost/url/format.hpp>
Expand Down Expand Up @@ -86,15 +85,32 @@ inline void
json["Name"] = "JsonSchemaFile Collection";
json["Description"] = "Collection of JsonSchemaFiles";
nlohmann::json::array_t members;
for (std::string_view schema : schemas)

std::error_code ec;
std::filesystem::directory_iterator dirList(
"/usr/share/www/redfish/v1/JsonSchemas", ec);
if (ec)
{
messages::internalError(asyncResp->res);
return;
}
for (const std::filesystem::path& file : dirList)
{
std::string filename = file.filename();
std::vector<std::string> split;
bmcweb::split(split, filename, '.');
if (split.empty())
{
continue;
}
nlohmann::json::object_t member;
member["@odata.id"] = boost::urls::format("/redfish/v1/JsonSchemas/{}",
schema);
split[0]);
members.emplace_back(std::move(member));
}

json["Members@odata.count"] = members.size();
json["Members"] = std::move(members);
json["Members@odata.count"] = schemas.size();
}

inline void jsonSchemaGet(App& app, const crow::Request& req,
Expand All @@ -106,40 +122,97 @@ inline void jsonSchemaGet(App& app, const crow::Request& req,
return;
}

if (std::ranges::find(schemas, schema) == schemas.end())
std::error_code ec;
std::filesystem::directory_iterator dirList(
"/usr/share/www/redfish/v1/JsonSchemas", ec);
if (ec)
{
messages::resourceNotFound(asyncResp->res, "JsonSchemaFile", schema);
return;
}
for (const std::filesystem::path& file : dirList)
{
std::string filename = file.filename();
std::vector<std::string> split;
bmcweb::split(split, filename, '.');
if (split.empty())
{
continue;
}
BMCWEB_LOG_DEBUG("Checking {}", split[0]);
if (split[0] != schema)
{
continue;
}

nlohmann::json& json = asyncResp->res.jsonValue;
json["@odata.id"] = boost::urls::format("/redfish/v1/JsonSchemas/{}",
schema);
json["@odata.type"] = "#JsonSchemaFile.v1_0_2.JsonSchemaFile";
json["Name"] = schema + " Schema File";
json["Description"] = schema + " Schema File Location";
json["Id"] = schema;
std::string schemaName = std::format("#{}.{}", schema, schema);
json["Schema"] = std::move(schemaName);
constexpr std::array<std::string_view, 1> languages{"en"};
json["Languages"] = languages;
json["Languages@odata.count"] = languages.size();

nlohmann::json::array_t locationArray;
nlohmann::json::object_t locationEntry;
locationEntry["Language"] = "en";

locationEntry["PublicationUri"] = boost::urls::format(
"http://redfish.dmtf.org/schemas/v1/{}", filename);
locationEntry["Uri"] = boost::urls::format(
"/redfish/v1/JsonSchemas/{}/{}", schema, filename);

locationArray.emplace_back(locationEntry);

json["Location"] = std::move(locationArray);
json["Location@odata.count"] = 1;
return;
}
messages::resourceNotFound(asyncResp->res, "JsonSchemaFile", schema);
}

nlohmann::json& json = asyncResp->res.jsonValue;
json["@odata.id"] = boost::urls::format("/redfish/v1/JsonSchemas/{}",
schema);
json["@odata.type"] = "#JsonSchemaFile.v1_0_2.JsonSchemaFile";
json["Name"] = schema + " Schema File";
json["Description"] = schema + " Schema File Location";
json["Id"] = schema;
std::string schemaName = "#";
schemaName += schema;
schemaName += ".";
schemaName += schema;
json["Schema"] = std::move(schemaName);
constexpr std::array<std::string_view, 1> languages{"en"};
json["Languages"] = languages;
json["Languages@odata.count"] = languages.size();

nlohmann::json::array_t locationArray;
nlohmann::json::object_t locationEntry;
locationEntry["Language"] = "en";
locationEntry["PublicationUri"] = "http://redfish.dmtf.org/schemas/v1/" +
schema + ".json";
locationEntry["Uri"] = boost::urls::format(
"/redfish/v1/JsonSchemas/{}/{}", schema, std::string(schema) + ".json");

locationArray.emplace_back(locationEntry);

json["Location"] = std::move(locationArray);
json["Location@odata.count"] = 1;
inline void
jsonSchemaGetFile(const crow::Request& /*req*/,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& schema, const std::string& schemaFile)
{
// Sanity check the filename
if (schemaFile.find_first_not_of(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.") !=
std::string::npos)
{
messages::resourceNotFound(asyncResp->res, "JsonSchemaFile", schema);
return;
}
// Schema path should look like /redfish/v1/JsonSchemas/Foo/Foo.x.json
// Make sure the two paths match.
if (!schemaFile.starts_with(schema))
{
messages::resourceNotFound(asyncResp->res, "JsonSchemaFile", schema);
return;
}
std::filesystem::path filepath("/usr/share/www/redfish/v1/JsonSchemas");
filepath /= schemaFile;
if (filepath.is_relative())
{
messages::resourceNotFound(asyncResp->res, "JsonSchemaFile", schema);
return;
}

if (!asyncResp->res.openFile(filepath))
{
BMCWEB_LOG_DEBUG("failed to read file");
asyncResp->res.result(
boost::beast::http::status::internal_server_error);
return;
}

messages::resourceNotFound(asyncResp->res, "JsonSchemaFile", schema);
}

inline void requestRoutesRedfish(App& app)
Expand All @@ -148,6 +221,10 @@ inline void requestRoutesRedfish(App& app)
.methods(boost::beast::http::verb::get)(
std::bind_front(redfishGet, std::ref(app)));

BMCWEB_ROUTE(app, "/redfish/v1/JsonSchemas/<str>/<str>")
.privileges(redfish::privileges::getJsonSchemaFile)
.methods(boost::beast::http::verb::get)(jsonSchemaGetFile);

BMCWEB_ROUTE(app, "/redfish/v1/JsonSchemas/<str>/")
.privileges(redfish::privileges::getJsonSchemaFileCollection)
.methods(boost::beast::http::verb::get)(
Expand Down
1 change: 1 addition & 0 deletions redfish-core/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
subdir('schema')
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit a529a6a

Please sign in to comment.