Minor fixes to make redfish pass compliance tests

1. Role members needs to be an array, not an object
2. Fix accounts schema to use the new user manager
3. Remove "status" field hardcodes
4. Hardcode chassisType to rackmount for now
5. Work around bug in get sub routes
6. Add ID to SessionService Schema

Change-Id: Ibb13d6ace747ac028e840638868c3a01d65dedfa
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
diff --git a/include/redfish_v1.hpp b/include/redfish_v1.hpp
index 52b9410..c28208d 100644
--- a/include/redfish_v1.hpp
+++ b/include/redfish_v1.hpp
@@ -43,6 +43,11 @@
   return result;
 }
 
+using ManagedObjectType = std::vector<std::pair<
+    dbus::object_path, boost::container::flat_map<
+                           std::string, boost::container::flat_map<
+                                            std::string, dbus::dbus_variant>>>>;
+
 template <typename... Middlewares>
 void request_routes(Crow<Middlewares...>& app) {
   CROW_ROUTE(app, "/redfish/")
@@ -54,14 +59,9 @@
   CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
       .methods(
           "GET"_method)([&](const crow::request& req, crow::response& res) {
-        boost::asio::io_service io;
-        auto bus = std::make_shared<dbus::connection>(io, dbus::bus::session);
-        dbus::endpoint user_list("org.openbmc.UserManager",
-                                 "/org/openbmc/UserManager/Users",
-                                 "org.openbmc.Enrol", "UserList");
-        bus->async_method_call(
+        crow::connections::system_bus->async_method_call(
             [&](const boost::system::error_code ec,
-                const std::vector<std::string>& users) {
+                const ManagedObjectType& users) {
               if (ec) {
                 res.code = 500;
               } else {
@@ -78,38 +78,75 @@
                     {"Members@odata.count", users.size()}};
                 nlohmann::json member_array = nlohmann::json::array();
                 int user_index = 0;
-                for (int user_index = 0; user_index < users.size();
-                     user_index++) {
+                for (auto& user : users) {
+                  const std::string& path = user.first.value;
+                  std::size_t last_index = path.rfind("/");
+                  if (last_index == std::string::npos) {
+                    last_index = 0;
+                  } else {
+                    last_index += 1;
+                  }
                   member_array.push_back(
                       {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
-                                         std::to_string(user_index)}});
+                                         path.substr(last_index)}});
                 }
                 res.json_value["Members"] = member_array;
               }
               res.end();
             },
-            user_list);
+            {"xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"});
       });
 
-  CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts/<int>/")
+  CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
       .methods("GET"_method)([](const crow::request& req, crow::response& res,
-                                int account_index) {
-        res.json_value = {
-            {"@odata.context",
-             "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
-            {"@odata.id", "/redfish/v1/AccountService/Accounts/1"},
-            {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
-            {"Id", "1"},
-            {"Name", "User Account"},
-            {"Description", "User Account"},
-            {"Enabled", false},
-            {"Password", nullptr},
-            {"UserName", "anonymous"},
-            {"RoleId", "NoAccess"},
-            {"Links",
-             {{"Role",
-               {{"@odata.id", "/redfish/v1/AccountService/Roles/NoAccess"}}}}}};
-        res.end();
+                                const std::string& account_name) {
+
+        crow::connections::system_bus->async_method_call(
+            [&, account_name{std::move(account_name)} ](
+                const boost::system::error_code ec,
+                const ManagedObjectType& users) {
+              if (ec) {
+                res.code = 500;
+              } else {
+                for (auto& user : users) {
+                  const std::string& path = user.first.value;
+                  std::size_t last_index = path.rfind("/");
+                  if (last_index == std::string::npos) {
+                    last_index = 0;
+                  } else {
+                    last_index += 1;
+                  }
+                  if (path.substr(last_index) == account_name) {
+                    res.json_value = {
+                        {"@odata.context",
+                         "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
+                        {"@odata.id", "/redfish/v1/AccountService/Accounts/1"},
+                        {"@odata.type",
+                         "#ManagerAccount.v1_0_3.ManagerAccount"},
+                        {"Id", "1"},
+                        {"Name", "User Account"},
+                        {"Description", "User Account"},
+                        {"Enabled", false},
+                        {"Password", nullptr},
+                        {"UserName", account_name},
+                        {"RoleId", "Administrator"},
+                        {"Links",
+                         {{"Role",
+                           {{"@odata.id",
+                             "/redfish/v1/AccountService/Roles/"
+                             "Administrator"}}}}}};
+                    break;
+                  }
+                }
+                if (res.json_value.is_null()) {
+                  res.code = 404;
+                }
+              }
+              res.end();
+            },
+            {"xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"});
       });
 }
 }  // namespace redfish
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
index b58ff11..53b67a4 100644
--- a/redfish-core/lib/account_service.hpp
+++ b/redfish-core/lib/account_service.hpp
@@ -22,9 +22,7 @@
 class AccountService : public Node {
  public:
   template <typename CrowApp>
-  AccountService(CrowApp& app)
-      : Node(app,
-             "/redfish/v1/AccountService/") {
+  AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/") {
     Node::json["@odata.id"] = "/redfish/v1/AccountService";
     Node::json["@odata.type"] = "#AccountService.v1_1_0.AccountService";
     Node::json["@odata.context"] =
@@ -32,9 +30,6 @@
     Node::json["Id"] = "AccountService";
     Node::json["Description"] = "BMC User Accounts";
     Node::json["Name"] = "Account Service";
-    Node::json["Status"]["State"] = "Enabled";
-    Node::json["Status"]["Health"] = "OK";
-    Node::json["Status"]["HealthRollup"] = "OK";
     Node::json["ServiceEnabled"] = true;
     Node::json["MinPasswordLength"] = 1;
     Node::json["MaxPasswordLength"] = 20;
diff --git a/redfish-core/lib/chassis.hpp b/redfish-core/lib/chassis.hpp
index 8f88eb1..02a614b 100644
--- a/redfish-core/lib/chassis.hpp
+++ b/redfish-core/lib/chassis.hpp
@@ -213,6 +213,7 @@
     Node::json["@odata.id"] = "/redfish/v1/Chassis";
     Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
     Node::json["Name"] = "Chassis Collection";
+    Node::json["ChassisType"] = "RackMount";
 
     entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
                         {crow::HTTPMethod::HEAD, {{"Login"}}},
@@ -256,8 +257,8 @@
                  output) {
               json_response[chassis_item.first] = chassis_item.second;
             }
-            json_response["Id"] = chassis_id;
 
+            json_response["Id"] = chassis_id;
             // prepare respond, and send
             res.json_value = json_response;
           } else {
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index ad042cb..7032a20 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -29,9 +29,6 @@
     Node::json["Name"] = "OpenBmc Manager";
     Node::json["Description"] = "Baseboard Management Controller";
     Node::json["PowerState"] = "On";
-    Node::json["Status"]["Health"] = "OK";
-    Node::json["Status"]["HealthRollup"] = "OK";
-    Node::json["Status"]["State"] = "Enabled";
     Node::json["UUID"] =
         app.template get_middleware<crow::PersistentData::Middleware>()
             .system_uuid;
@@ -80,7 +77,7 @@
         "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
     Node::json["Name"] = "Manager Collection";
     Node::json["Members@odata.count"] = 1;
-    Node::json["Members"] = {{"@odata.id", "/redfish/v1/Managers/openbmc"}};
+    Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/openbmc"}}};
 
     entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
                         {crow::HTTPMethod::HEAD, {{"Login"}}},
diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp
index 326d5e0..4e429e8 100644
--- a/redfish-core/lib/redfish_sessions.hpp
+++ b/redfish-core/lib/redfish_sessions.hpp
@@ -25,7 +25,7 @@
 class Sessions : public Node {
  public:
   Sessions(CrowApp& app)
-      : Node(app, "/redfish/v1/SessionService/Sessions/<str>", std::string()) {
+      : Node(app, "/redfish/v1/SessionService/Sessions/<str>/", std::string()) {
     Node::json["@odata.type"] = "#Session.v1_0_2.Session";
     Node::json["@odata.context"] = "/redfish/v1/$metadata#Session.Session";
     Node::json["Name"] = "User Session";
@@ -236,12 +236,10 @@
     Node::json["@odata.context"] =
         "/redfish/v1/$metadata#SessionService.SessionService";
     Node::json["Name"] = "Session Service";
+    Node::json["Id"] = "SessionService";
     Node::json["Description"] = "Session Service";
     Node::json["SessionTimeout"] =
         crow::PersistentData::session_store->get_timeout_in_seconds();
-    Node::json["Status"]["State"] = "Enabled";
-    Node::json["Status"]["Health"] = "OK";
-    Node::json["Status"]["HealthRollup"] = "OK";
     Node::json["ServiceEnabled"] = true;
 
     entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
diff --git a/redfish-core/lib/roles.hpp b/redfish-core/lib/roles.hpp
index fc804c2..7b7a804 100644
--- a/redfish-core/lib/roles.hpp
+++ b/redfish-core/lib/roles.hpp
@@ -62,7 +62,7 @@
     Node::json["Description"] = "BMC User Roles";
     Node::json["Members@odata.count"] = 1;
     Node::json["Members"] = {
-        {"@odata.id", "/redfish/v1/AccountService/Roles/Administrator"}};
+        {{"@odata.id", "/redfish/v1/AccountService/Roles/Administrator"}}};
 
     entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
                         {crow::HTTPMethod::HEAD, {{"Login"}}},
@@ -76,6 +76,11 @@
   void doGet(crow::response& res, const crow::request& req,
              const std::vector<std::string>& params) override {
     res.json_value = Node::json;
+    // This is a short term solution to work around a bug.  GetSubroutes
+    // accidentally recognizes the Roles/Administrator route as a subroute
+    // (because it's hardcoded to a single entity).  Remove this line when that
+    // is resolved
+    res.json_value.erase("Administrator");
     res.end();
   }
 };