Prevent users from logging in while BMC is not yet ready.

Reject user logins while BMC_READY state has not been reached yet,
and report the reason in response.

Resolves: openbmc/openbmc#2974

This behavior may be enabled by appending `--with-bmc-check` to
command line arguments.

When it is enabled it maybe temporary disabled by sending `force`
flag with the login request:
```
{
    "data": [ "username", "password" ],
    "force": true
}
```

Tested: When trying to login in REST receiving response with code 503
while BMC is booting.
Change-Id: I04fce09de2b7a3074b5253346a87773641fd57d0
Signed-off-by: Alexander Filippov <a.filippov@yadro.com>
diff --git a/module/obmc/wsgi/apps/rest_dbus.py b/module/obmc/wsgi/apps/rest_dbus.py
index ffbab94..bf4fe7c 100644
--- a/module/obmc/wsgi/apps/rest_dbus.py
+++ b/module/obmc/wsgi/apps/rest_dbus.py
@@ -15,6 +15,7 @@
 # permissions and limitations under the License.
 
 import os
+import sys
 import dbus
 import dbus.exceptions
 import json
@@ -630,8 +631,13 @@
     no_user_str = "No user logged in"
     bad_json_str = "Expecting request format { 'data': " \
         "[<username>, <password>] }, got '%s'"
+    bmc_not_ready_str = "BMC is not ready (booting)"
     _require_auth = None
     MAX_SESSIONS = 16
+    BMCSTATE_IFACE = 'xyz.openbmc_project.State.BMC'
+    BMCSTATE_PATH = '/xyz/openbmc_project/state/bmc0'
+    BMCSTATE_PROPERTY = 'CurrentBMCState'
+    BMCSTATE_READY = 'xyz.openbmc_project.State.BMC.BMCState.Ready'
 
     def __init__(self, app, bus):
         super(SessionHandler, self).__init__(
@@ -696,6 +702,15 @@
         if not self.authenticate(*request.parameter_list):
             abort(401, self.bad_passwd_str)
 
+        force = False
+        try:
+            force = request.json.get('force')
+        except (ValueError, AttributeError, KeyError, TypeError):
+            force = False
+
+        if not force and not self.is_bmc_ready():
+            abort(503, self.bmc_not_ready_str)
+
         user = request.parameter_list[0]
         session = self.new_session()
         session['user'] = user
@@ -705,6 +720,22 @@
             httponly=True)
         return self.login_str % (user, 'in')
 
+    def is_bmc_ready(self):
+        if not self.app.with_bmc_check:
+            return True
+
+        try:
+            obj = self.bus.get_object(self.BMCSTATE_IFACE, self.BMCSTATE_PATH)
+            iface = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+            state = iface.Get(self.BMCSTATE_IFACE, self.BMCSTATE_PROPERTY)
+            if state == self.BMCSTATE_READY:
+                return True
+
+        except dbus.exceptions.DBusException:
+            pass
+
+        return False
+
     def find(self, **kw):
         pass
 
@@ -1419,6 +1450,7 @@
         super(App, self).__init__(autojson=False)
 
         self.have_wsock = kw.get('have_wsock', False)
+        self.with_bmc_check = '--with-bmc-check' in sys.argv
 
         self.bus = dbus.SystemBus()
         self.mapper = obmc.mapper.Mapper(self.bus)