bmcweb: move ethernet VLAN to readJson

This commit moves the various vlan interfaces to use the existing
std::vector based implementations, and not the existing implementations.

Change-Id: Id2503d5e2f1503b61ec7dbdb25098611382b24c5
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
diff --git a/redfish-core/lib/ethernet.hpp b/redfish-core/lib/ethernet.hpp
index a7018a4..70e5536 100644
--- a/redfish-core/lib/ethernet.hpp
+++ b/redfish-core/lib/ethernet.hpp
@@ -911,139 +911,74 @@
     }
 
     void handleIPv4Patch(
-        const std::string &ifaceId, const nlohmann::json &input,
+        const std::string &ifaceId, std::vector<nlohmann::json> &input,
         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
         const std::shared_ptr<AsyncResp> asyncResp)
     {
-        if (!input.is_array())
-        {
-            messages::propertyValueTypeError(asyncResp->res, input.dump(),
-                                             "IPv4Addresses");
-            return;
-        }
-
-        // According to Redfish PATCH definition, size must be at least equal
-        if (input.size() < ipv4Data.size())
-        {
-            messages::propertyValueFormatError(asyncResp->res, input.dump(),
-                                               "IPv4Addresses");
-            return;
-        }
-
         int entryIdx = 0;
         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
             ipv4Data.begin();
-        for (const nlohmann::json &thisJson : input)
+        for (nlohmann::json &thisJson : input)
         {
             std::string pathString =
                 "IPv4Addresses/" + std::to_string(entryIdx);
-            // Check that entry is not of some unexpected type
-            if (!thisJson.is_object() && !thisJson.is_null())
-            {
-                messages::propertyValueTypeError(asyncResp->res,
-                                                 thisJson.dump(),
-                                                 pathString + "/IPv4Address");
 
-                continue;
+            std::optional<std::string> address;
+            std::optional<std::string> addressOrigin;
+            std::optional<std::string> subnetMask;
+            std::optional<std::string> gateway;
+
+            if (!json_util::readJson(thisJson, asyncResp->res, "Address",
+                                     address, "AddressOrigin", addressOrigin,
+                                     "SubnetMask", subnetMask, "Gateway",
+                                     gateway))
+            {
+                return;
             }
 
-            nlohmann::json::const_iterator addressFieldIt =
-                thisJson.find("Address");
-            const std::string *addressField = nullptr;
-            if (addressFieldIt != thisJson.end())
+            if (address)
             {
-                addressField = addressFieldIt->get_ptr<const std::string *>();
-                if (addressField == nullptr)
+                if (!ipv4VerifyIpAndGetBitcount(*address))
                 {
-                    messages::propertyValueFormatError(asyncResp->res,
-                                                       addressFieldIt->dump(),
+                    messages::propertyValueFormatError(asyncResp->res, *address,
                                                        pathString + "/Address");
-                    continue;
-                }
-                else
-                {
-                    if (!ipv4VerifyIpAndGetBitcount(*addressField))
-                    {
-                        messages::propertyValueFormatError(
-                            asyncResp->res, *addressField,
-                            pathString + "/Address");
-                        continue;
-                    }
+                    return;
                 }
             }
 
-            std::optional<uint8_t> prefixLength;
-            const std::string *subnetField = nullptr;
-            nlohmann::json::const_iterator subnetFieldIt =
-                thisJson.find("SubnetMask");
-            if (subnetFieldIt != thisJson.end())
+            uint8_t prefixLength = 0;
+            if (subnetMask)
             {
-                subnetField = subnetFieldIt->get_ptr<const std::string *>();
-                if (subnetField == nullptr)
+                if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
                 {
                     messages::propertyValueFormatError(
-                        asyncResp->res, *subnetField,
+                        asyncResp->res, *subnetMask,
                         pathString + "/SubnetMask");
-                    continue;
-                }
-                else
-                {
-                    prefixLength = 0;
-                    if (!ipv4VerifyIpAndGetBitcount(*subnetField,
-                                                    &*prefixLength))
-                    {
-                        messages::propertyValueFormatError(
-                            asyncResp->res, *subnetField,
-                            pathString + "/SubnetMask");
-                        continue;
-                    }
+                    return;
                 }
             }
-
             std::string addressOriginInDBusFormat;
-            const std::string *addressOriginField = nullptr;
-            nlohmann::json::const_iterator addressOriginFieldIt =
-                thisJson.find("AddressOrigin");
-            if (addressOriginFieldIt != thisJson.end())
+            if (addressOrigin)
             {
-                const std::string *addressOriginField =
-                    addressOriginFieldIt->get_ptr<const std::string *>();
-                if (addressOriginField == nullptr)
+                // Get Address origin in proper format
+                addressOriginInDBusFormat =
+                    translateAddressOriginRedfishToDbus(*addressOrigin);
+                if (addressOriginInDBusFormat.empty())
                 {
-                    messages::propertyValueFormatError(
-                        asyncResp->res, *addressOriginField,
+                    messages::propertyValueNotInList(
+                        asyncResp->res, *addressOrigin,
                         pathString + "/AddressOrigin");
-                    continue;
-                }
-                else
-                {
-                    // Get Address origin in proper format
-                    addressOriginInDBusFormat =
-                        translateAddressOriginRedfishToDbus(
-                            *addressOriginField);
-                    if (addressOriginInDBusFormat.empty())
-                    {
-                        messages::propertyValueNotInList(
-                            asyncResp->res, *addressOriginField,
-                            pathString + "/AddressOrigin");
-                        continue;
-                    }
+                    return;
                 }
             }
 
-            nlohmann::json::const_iterator gatewayFieldIt =
-                thisJson.find("Gateway");
-            const std::string *gatewayField = nullptr;
-            if (gatewayFieldIt != thisJson.end())
+            if (gateway)
             {
-                const std::string *gatewayField =
-                    gatewayFieldIt->get_ptr<const std::string *>();
-                if (gatewayField == nullptr ||
-                    !ipv4VerifyIpAndGetBitcount(*gatewayField))
+                if (!ipv4VerifyIpAndGetBitcount(*gateway))
                 {
-                    messages::propertyValueFormatError(
-                        asyncResp->res, *gatewayField, pathString + "/Gateway");
-                    continue;
+                    messages::propertyValueFormatError(asyncResp->res, *gateway,
+                                                       pathString + "/Gateway");
+                    return;
                 }
             }
 
@@ -1074,11 +1009,10 @@
                 else if (thisJson.is_object())
                 {
                     // Apply changes
-                    if (addressField != nullptr)
+                    if (address)
                     {
                         auto callback =
-                            [asyncResp, entryIdx,
-                             addressField{std::string(*addressField)}](
+                            [asyncResp, entryIdx, address = *address](
                                 const boost::system::error_code ec) {
                                 if (ec)
                                 {
@@ -1087,7 +1021,7 @@
                                 }
                                 asyncResp->res
                                     .jsonValue["IPv4Addresses"][std::to_string(
-                                        entryIdx)]["Address"] = addressField;
+                                        entryIdx)]["Address"] = address;
                             };
 
                         crow::connections::systemBus->async_method_call(
@@ -1096,29 +1030,28 @@
                                 "/ipv4/" + thisData->id,
                             "org.freedesktop.DBus.Properties", "Set",
                             "xyz.openbmc_project.Network.IP", "Address",
-                            std::variant<std::string>(*addressField));
+                            std::variant<std::string>(*address));
                     }
 
-                    if (prefixLength && subnetField != nullptr)
+                    if (subnetMask)
                     {
                         changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
-                                                     thisData->id, *subnetField,
-                                                     *prefixLength, asyncResp);
+                                                     thisData->id, *subnetMask,
+                                                     prefixLength, asyncResp);
                     }
 
-                    if (!addressOriginInDBusFormat.empty() &&
-                        addressOriginField != nullptr)
+                    if (addressOrigin)
                     {
                         changeIPv4Origin(ifaceId, entryIdx, thisData->id,
-                                         *addressOriginField,
+                                         *addressOrigin,
                                          addressOriginInDBusFormat, asyncResp);
                     }
 
-                    if (gatewayField != nullptr)
+                    if (gateway)
                     {
                         auto callback =
                             [asyncResp, entryIdx,
-                             gatewayField{std::string(*gatewayField)}](
+                             gateway{std::string(*gateway)}](
                                 const boost::system::error_code ec) {
                                 if (ec)
                                 {
@@ -1128,7 +1061,7 @@
                                 asyncResp->res
                                     .jsonValue["IPv4Addresses"][std::to_string(
                                         entryIdx)]["Gateway"] =
-                                    std::move(gatewayField);
+                                    std::move(gateway);
                             };
 
                         crow::connections::systemBus->async_method_call(
@@ -1137,7 +1070,7 @@
                                 "/ipv4/" + thisData->id,
                             "org.freedesktop.DBus.Properties", "Set",
                             "xyz.openbmc_project.Network.IP", "Gateway",
-                            std::variant<std::string>(*gatewayField));
+                            std::variant<std::string>(*gateway));
                     }
                 }
                 thisData++;
@@ -1145,29 +1078,29 @@
             else
             {
                 // Create IPv4 with provided data
-                if (gatewayField == nullptr)
+                if (!gateway)
                 {
                     messages::propertyMissing(asyncResp->res,
                                               pathString + "/Gateway");
                     continue;
                 }
 
-                if (addressField == nullptr)
+                if (!address)
                 {
                     messages::propertyMissing(asyncResp->res,
                                               pathString + "/Address");
                     continue;
                 }
 
-                if (!prefixLength)
+                if (!subnetMask)
                 {
                     messages::propertyMissing(asyncResp->res,
                                               pathString + "/SubnetMask");
                     continue;
                 }
 
-                createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField,
-                           *addressField, asyncResp);
+                createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
+                           asyncResp);
                 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson;
             }
             entryIdx++;
@@ -1286,8 +1219,8 @@
 
         std::optional<nlohmann::json> vlan;
         std::optional<std::string> hostname;
-        std::optional<nlohmann::json> ipv4Addresses;
-        std::optional<nlohmann::json> ipv6Addresses;
+        std::optional<std::vector<nlohmann::json>> ipv4Addresses;
+        std::optional<std::vector<nlohmann::json>> ipv6Addresses;
 
         if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname,
                                  "IPv4Addresses", ipv4Addresses,
@@ -1356,8 +1289,15 @@
 
                 if (ipv4Addresses)
                 {
-                    handleIPv4Patch(iface_id, *ipv4Addresses, ipv4Data,
-                                    asyncResp);
+                    // TODO(ed) for some reason the capture of ipv4Addresses
+                    // above is returning a const value, not a non-const value.
+                    // This doesn't really work for us, as we need to be able to
+                    // efficiently move out the intermedia nlohmann::json
+                    // objects. This makes a copy of the structure, and operates
+                    // on that, but could be done more efficiently
+                    std::vector<nlohmann::json> ipv4 =
+                        std::move(*ipv4Addresses);
+                    handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
                 }
 
                 if (ipv6Addresses)