Seed code for hostcli
[ta/hostcli.git] / src / hostcli / resthandler.py
diff --git a/src/hostcli/resthandler.py b/src/hostcli/resthandler.py
new file mode 100644 (file)
index 0000000..0f1d16d
--- /dev/null
@@ -0,0 +1,132 @@
+# Copyright 2019 Nokia
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import logging
+import requests
+import os
+
+API_NAME = 'resthandler'
+LOG = logging.getLogger(__name__)
+
+def make_instance(instance):
+    return RestRequest(instance)
+
+class RestRequest(object):
+    """ RestRequest object
+        This module can be used in the context of hostcli rest implementations.
+        Example usage is:
+            def take_action(self, parsed_args):
+                req = self.app.client_manager.resthandler
+                ret = req.get("has/v1/cluster", decode_json=True)
+                status = ret['data']
+                columns = ('admin-state',
+                           'running-state',
+                           'role'
+                          )
+                data = (status['admin-state'],
+                        status['running-state'],
+                        status['role']
+                        )
+                return (columns, data)
+        Why:
+            This module will fill the needed information for authentication.
+            The authentication will be based on keystone.
+        Notes:
+            The object will fill the prefix to the request. So it's not mandatory
+            to write it. This information will be populated from the endpoint of rest frame.
+    """
+    def __init__(self, app_instance):
+        self.instance = app_instance
+        if self.instance._auth_required:
+            self.token = self.instance.auth_ref.auth_token
+            self.auth_ref = self.instance.auth_ref
+            self.url = self.auth_ref.service_catalog.url_for(service_type="restfulapi",
+                                                             service_name="restfulframework",
+                                                             interface=self.instance.interface)
+        else:
+            if 'OS_REST_URL' in os.environ:
+                self.url = os.environ['OS_REST_URL']
+            else:
+                raise Exception("OS_REST_URL environment variable missing")
+
+    def get(self, url, data=None, params=None, decode_json=True):
+        return self._operation("get", url, data=data, params=params, decode_json=decode_json)
+
+    def post(self, url, data=None, params=None, decode_json=True):
+        return self._operation("post", url, data=data, params=params, decode_json=decode_json)
+
+    def put(self, url, data=None, params=None, decode_json=True):
+        return self._operation("put", url, data=data, params=params, decode_json=decode_json)
+
+    def patch(self, url, data=None, params=None, decode_json=True):
+        return self._operation("patch", url, data=data, params=params, decode_json=decode_json)
+
+    def delete(self, url, data=None, params=None, decode_json=True):
+        return self._operation("delete", url, data=data, params=params, decode_json=decode_json)
+
+    def _operation(self, oper, url, data=None, params=None, decode_json=True):
+
+        operation = getattr(requests, oper, None)
+
+        if not operation:
+            raise NameError("Operation %s not found" % oper)
+
+        if not url.startswith("http"):
+            url = self.url + '/' + url
+
+        LOG.debug("Working with url %s" % url)
+
+        # Disable request debug logs
+        logging.getLogger("requests").setLevel(logging.WARNING)
+
+        # HACK:Check if the authentication will expire and if so then renew it
+        if self.instance._auth_required and self.auth_ref.will_expire_soon():
+            LOG.debug("Session will expire soon... Renewing token")
+            self.instance._auth_setup_completed = False
+            self.instance._auth_ref = None
+            self.token = self.instance.auth_ref.auth_token
+        else:
+            LOG.debug("Session is solid. Using existing token.")
+
+        # Add security headers
+        arguments = {}
+        headers = {'User-Agent': 'HostCli'}
+
+        if self.instance._auth_required:
+            headers.update({'X-Auth-Token': self.token})
+
+        if data:
+            if isinstance(data, dict):
+                arguments["json"] = data
+                headers["Content-Type"] = "application/json"
+            else:
+                arguments["data"] = data
+                headers["Content-Type"] = "text/plain"
+
+        arguments["headers"] = headers
+
+        if params:
+            arguments["params"] = params
+
+        ret = operation(url, **arguments)
+
+        if decode_json:
+            ret.raise_for_status()
+            try:
+                return ret.json()
+            except ValueError:
+                return {}
+        else:
+            return ret