diff options
author | Joshi-Mansi <mansi.joshi@linux.intel.com> | 2020-03-10 16:03:36 +0300 |
---|---|---|
committer | mansi.joshi <mansi.joshi@linux.intel.com> | 2020-04-01 21:45:28 +0300 |
commit | ab6554f1d8197753cfb430a72798dde6f4461552 (patch) | |
tree | 83a06c79e788526236c1589e4815a8bd59e92129 | |
parent | 3c27ed3bb4ce887d2bd691a69314fe71c6a95942 (diff) | |
download | bmcweb-ab6554f1d8197753cfb430a72798dde6f4461552.tar.xz |
[Redfish-Ethernet Inf] Enable Read/Write for FQDN
Enabling read/write requirement of FQDN in Ethernet Interface Schema
to make it OCP compliant.
Tested:
1. Tested using PATCH:
- https://bmc-ip/redfish/v1/Managers/bmc/EthernetInterfaces/eth-id
{"FQDN": "hostname.domainname"}
GET Response- "FQDN": "hostname.domainname" //Success
- When given invalid hostname/domainname
Error Message "propertyValueFormatError"
2. Ran the Redfish validator and no new issues found.
Signed-off-by: Joshi-Mansi <mansi.joshi@linux.intel.com>
Change-Id: Ief2e94f8b499be59196b0e7073ceffe8d49268ca
-rw-r--r-- | redfish-core/lib/ethernet.hpp | 116 |
1 files changed, 106 insertions, 10 deletions
diff --git a/redfish-core/lib/ethernet.hpp b/redfish-core/lib/ethernet.hpp index 0a2a1858b7..56e1a1508b 100644 --- a/redfish-core/lib/ethernet.hpp +++ b/redfish-core/lib/ethernet.hpp @@ -21,6 +21,7 @@ #include <error_messages.hpp> #include <node.hpp> #include <optional> +#include <regex> #include <utils/json_utils.hpp> #include <variant> @@ -1084,7 +1085,13 @@ class EthernetInterface : public Node void handleHostnamePatch(const std::string &hostname, const std::shared_ptr<AsyncResp> asyncResp) { - asyncResp->res.jsonValue["HostName"] = hostname; + // SHOULD handle host names of up to 255 characters(RFC 1123) + if (hostname.length() > 255) + { + messages::propertyValueFormatError(asyncResp->res, hostname, + "HostName"); + return; + } crow::connections::systemBus->async_method_call( [asyncResp](const boost::system::error_code ec) { if (ec) @@ -1099,6 +1106,84 @@ class EthernetInterface : public Node std::variant<std::string>(hostname)); } + void handleDomainnamePatch(const std::string &ifaceId, + const std::string &domainname, + const std::shared_ptr<AsyncResp> asyncResp) + { + std::vector<std::string> vectorDomainname = {domainname}; + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + messages::internalError(asyncResp->res); + } + }, + "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network/" + ifaceId, + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.EthernetInterface", "DomainName", + std::variant<std::vector<std::string>>(vectorDomainname)); + } + + void handleFqdnPatch(const std::string &ifaceId, const std::string &fqdn, + const std::shared_ptr<AsyncResp> asyncResp) + { + // Total length of FQDN must not exceed 255 characters(RFC 1035) + if (fqdn.length() > 255) + { + messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); + return; + } + + size_t pos = fqdn.find('.'); + if (pos == std::string::npos) + { + messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); + return; + } + + std::string hostname; + std::string domainname; + domainname = (fqdn).substr(pos + 1); + hostname = (fqdn).substr(0, pos); + + if (!isHostnameValid(hostname) || !isDomainnameValid(domainname)) + { + messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); + return; + } + + handleHostnamePatch(hostname, asyncResp); + handleDomainnamePatch(ifaceId, domainname, asyncResp); + } + + bool isHostnameValid(const std::string &hostname) + { + // A valid host name can never have the dotted-decimal form (RFC 1123) + if (std::all_of(hostname.begin(), hostname.end(), ::isdigit)) + { + return false; + } + // Each label(hostname/subdomains) within a valid FQDN + // MUST handle host names of up to 63 characters (RFC 1123) + // labels cannot start or end with hyphens (RFC 952) + // labels can start with numbers (RFC 1123) + const std::regex pattern( + "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$"); + + return std::regex_match(hostname, pattern); + } + + bool isDomainnameValid(const std::string &domainname) + { + // Can have multiple subdomains + // Top Level Domain's min length is 2 character + const std::regex pattern("^([A-Za-z0-9][a-zA-Z0-9\\-]{1,61}|[a-zA-Z0-9]" + "{1,30}\\.)*[a-zA-Z]{2,}$"); + + return std::regex_match(domainname, pattern); + } + void handleMACAddressPatch(const std::string &ifaceId, const std::string &macAddress, const std::shared_ptr<AsyncResp> &asyncResp) @@ -1705,11 +1790,16 @@ class EthernetInterface : public Node if (!ethData.hostname.empty()) { json_response["HostName"] = ethData.hostname; + + // When domain name is empty then it means, that it is a network + // without domain names, and the host name itself must be treated as + // FQDN + std::string FQDN = std::move(ethData.hostname); if (!ethData.domainnames.empty()) { - json_response["FQDN"] = - ethData.hostname + "." + ethData.domainnames[0]; + FQDN += "." + ethData.domainnames[0]; } + json_response["FQDN"] = FQDN; } json_response["VLANs"] = { @@ -1828,6 +1918,7 @@ class EthernetInterface : public Node const std::string &iface_id = params[0]; std::optional<std::string> hostname; + std::optional<std::string> fqdn; std::optional<std::string> macAddress; std::optional<std::string> ipv6DefaultGateway; std::optional<nlohmann::json> ipv4StaticAddresses; @@ -1840,12 +1931,12 @@ class EthernetInterface : public Node DHCPParameters v6dhcpParms; if (!json_util::readJson( - req, res, "HostName", hostname, "IPv4StaticAddresses", - ipv4StaticAddresses, "MACAddress", macAddress, - "StaticNameServers", staticNameServers, "IPv6DefaultGateway", - ipv6DefaultGateway, "IPv6StaticAddresses", ipv6StaticAddresses, - "DHCPv4", dhcpv4, "DHCPv6", dhcpv6, "InterfaceEnabled", - interfaceEnabled)) + req, res, "HostName", hostname, "FQDN", fqdn, + "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress", + macAddress, "StaticNameServers", staticNameServers, + "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses", + ipv6StaticAddresses, "DHCPv4", dhcpv4, "DHCPv6", dhcpv6, + "InterfaceEnabled", interfaceEnabled)) { return; } @@ -1879,7 +1970,7 @@ class EthernetInterface : public Node getEthernetIfaceData( iface_id, [this, asyncResp, iface_id, hostname = std::move(hostname), - macAddress = std::move(macAddress), + fqdn = std::move(fqdn), macAddress = std::move(macAddress), ipv4StaticAddresses = std::move(ipv4StaticAddresses), ipv6DefaultGateway = std::move(ipv6DefaultGateway), ipv6StaticAddresses = std::move(ipv6StaticAddresses), @@ -1912,6 +2003,11 @@ class EthernetInterface : public Node handleHostnamePatch(*hostname, asyncResp); } + if (fqdn) + { + handleFqdnPatch(iface_id, *fqdn, asyncResp); + } + if (macAddress) { handleMACAddressPatch(iface_id, *macAddress, asyncResp); |