Robot using DMTF redfish python library

Change-Id: Ie2b3945dd5b01a0834873d2dfe2436e33b140441
Signed-off-by: George Keishing <gkeishin@in.ibm.com>
diff --git a/lib/bmc_redfish.py b/lib/bmc_redfish.py
new file mode 100644
index 0000000..819dd63
--- /dev/null
+++ b/lib/bmc_redfish.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+
+r"""
+Using python based redfish library.
+Refer: https://github.com/DMTF/python-redfish-library
+"""
+
+import redfish
+import json
+
+
+class HTTPSBadRequestError(Exception):
+    r"""
+    BMC redfish generic raised method for error(s).
+    """
+    pass
+
+
+class bmc_redfish(object):
+
+    ROBOT_LIBRARY_SCOPE = "GLOBAL"
+
+    def __init__(self, hostname, username, password, *args, **kwargs):
+        r"""
+        Establish session connection to host.
+
+        Description of argument(s):
+        hostname       The host name or IP address of the server.
+        username       The username to be used to connect to the server.
+        password       The password to be used to connect to the server.
+        args/kwargs    Additional parms which are passed directly
+                       to the redfish_client function.
+        """
+
+        self._base_url_ = "https://" + hostname
+        self._username_ = username
+        self._password_ = password
+        self._default_prefix_ = "/redfish/v1"
+        self._robj_ = \
+            redfish.redfish_client(base_url=self._base_url_,
+                                   username=self._username_,
+                                   password=self._password_,
+                                   default_prefix=self._default_prefix_,
+                                   *args, **kwargs)
+        self._robj_.login(auth=redfish.AuthMethod.SESSION)
+        self._session_location_ = self._robj_.get_session_location()
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exception_type, exception_value, traceback):
+        self._robj_.logout()
+
+    def login(self, *args, **kwargs):
+        r"""
+        Call the corresponding RestClientBase method and return the result.
+
+        Description of argument(s):
+        args/kwargs     These are passed directly to the corresponding
+                        RestClientBase method.
+        """
+        self._robj_.__init__(self._base_url_, self._username_, self._password_)
+        self._robj_.login(auth=redfish.AuthMethod.SESSION)
+
+    def get(self, resource_path, *args, **kwargs):
+        r"""
+        Perform a GET request and return response.
+
+        Description of argument(s):
+        resource_path    URI resource relative path (e.g. "Systems/1").
+        args/kwargs      These are passed directly to the corresponding
+                         RestClientBase method.
+        """
+        self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path,
+                                               *args, **kwargs)
+        if self._rest_response_.status != 200:
+            raise HTTPSBadRequestError("GET Session location: %s, "
+                                       "return code: %d"
+                                       % (self._session_location_,
+                                          self._rest_response_.status))
+        return self._rest_response_
+
+    def post(self, resource_path, *args, **kwargs):
+        r"""
+        Perform a POST request.
+
+        Description of argument(s):
+        resource_path    URI resource relative path
+                         (e.g. "Systems/1/Actions/ComputerSystem.Reset").
+        args/kwargs      These are passed directly to the corresponding
+                         RestClientBase method.
+        """
+        self._rest_response_ = self._robj_.post('/redfish/v1/' + resource_path,
+                                                *args, **kwargs)
+        if self._rest_response_.status != 200:
+            raise HTTPSBadRequestError("POST Session location: %s, "
+                                       "return code: %d"
+                                       % (self._session_location_,
+                                          self._rest_response_.status))
+        return self._rest_response_
+
+    def patch(self, resource_path, *args, **kwargs):
+        r"""
+        Perform a POST request.
+
+        Description of argument(s):
+        resource_path    URI resource relative path
+        args/kwargs      These are passed directly to the corresponding
+                         RestClientBase method.
+        """
+        self._rest_response_ = self._robj_.patch('/redfish/v1/' + resource_path,
+                                                 *args, **kwargs)
+        if self._rest_response_.status != 200:
+            raise HTTPSBadRequestError("PATCH Session location: %s, "
+                                       "return code: %d"
+                                       % (self._session_location_,
+                                          self._rest_response_.status))
+        return self._rest_response_
+
+    def put(self, resource_path, actions, attr_data):
+        r"""
+        Perform a PUT request.
+
+        Description of argument(s):
+        resource_path    URI resource relative path.
+        args/kwargs      These are passed directly to the corresponding
+                         RestClientBase method.
+        """
+        self._rest_response_ = self._robj_.put('/redfish/v1/' + resource_path,
+                                               *args, **kwargs)
+        if self._rest_response_.status != 200:
+            raise HTTPSBadRequestError("PUT Session location: %s, "
+                                       "return code: %d"
+                                       % (self._session_location_,
+                                          self._rest_response_.status))
+        return self._rest_response_
+
+    def delete(self, resource_path):
+        r"""
+        Perform a DELETE request.
+
+        Description of argument(s):
+        resource_path  URI resource absoulute path
+                       (e.g. "/redfish/v1/SessionService/Sessions/8d1a9wiiNL").
+        """
+        self._rest_response_ = self._robj_.delete(resource_path)
+        if self._rest_response_.status != 200:
+            raise HTTPSBadRequestError("Session location: %s, "
+                                       "return code: %d"
+                                       % (self._session_location_,
+                                          self._rest_response_.status))
+        return self._rest_response_
+
+    def logout(self):
+        r"""
+        Logout redfish connection session.
+        """
+        self._robj_.logout()
+
+    def list_request(self, resource_path):
+        r"""
+        Perform a GET list request and return available resource paths.
+
+        Description of argument(s):
+        resource_path    URI resource relative path (e.g. "Systems/1").
+        """
+
+        self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path)
+
+        global resource_list
+        resource_list = []
+        self.walk_nested_dict(self._rest_response_.dict)
+
+        if not resource_list:
+            return uri_path
+
+        for resource in resource_list:
+            self._rest_response_ = self._robj_.get(resource)
+            if self._rest_response_.status != 200:
+                continue
+            self.walk_nested_dict(self._rest_response_.dict)
+
+        resource_list.sort()
+        return json.dumps(resource_list, sort_keys=True,
+                          indent=4, separators=(',', ': '))
+
+    def enumerate_request(self, resource_path):
+        r"""
+        Perform a GET enumerate request and return available resource paths.
+
+        Description of argument(s):
+        resource_path    URI resource relative path (e.g. "Systems/1").
+        """
+
+        self._rest_response_ = self.list_request(resource_path)
+
+        resource_dict = {}
+        for resource in json.loads(self._rest_response_):
+            self._rest_response_ = self._robj_.get(resource)
+            if self._rest_response_.status != 200:
+                continue
+            resource_dict[resource] = self._rest_response_.dict
+
+        return json.dumps(resource_dict, sort_keys=True,
+                          indent=4, separators=(',', ': '))
+
+    def walk_nested_dict(self, data):
+        r"""
+        Parse through the nested dictionary and get the resource id paths.
+
+        Description of argument(s):
+        data    Nested dictionary data from response message.
+        """
+
+        for key, value in data.items():
+            if isinstance(value, dict):
+                self.walk_nested_dict(value)
+            else:
+                if 'Members' == key:
+                    if isinstance(value, list):
+                        for index in value:
+                            if index['@odata.id'] not in resource_list:
+                                resource_list.append(index['@odata.id'])
+                if '@odata.id' == key:
+                    if value not in resource_list and not value.endswith('/'):
+                        resource_list.append(value)
diff --git a/lib/bmc_redfish_resource.robot b/lib/bmc_redfish_resource.robot
new file mode 100644
index 0000000..a0e2c3f
--- /dev/null
+++ b/lib/bmc_redfish_resource.robot
@@ -0,0 +1,8 @@
+*** Settings ***
+Documentation   BMC redfish resource keyword.
+
+Library         ../lib/bmc_redfish.py
+...             ${OPENBMC_HOST}  ${OPENBMC_USERNAME}  ${OPENBMC_PASSWORD}
+...              WITH NAME    redfish
+
+*** Keywords ***