Seed code for hostcli
[ta/hostcli.git] / src / hostcli / resthandler.py
1 # Copyright 2019 Nokia
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15
16 import logging
17 import requests
18 import os
19
20 API_NAME = 'resthandler'
21 LOG = logging.getLogger(__name__)
22
23 def make_instance(instance):
24     return RestRequest(instance)
25
26 class RestRequest(object):
27     """ RestRequest object
28         This module can be used in the context of hostcli rest implementations.
29         Example usage is:
30             def take_action(self, parsed_args):
31                 req = self.app.client_manager.resthandler
32                 ret = req.get("has/v1/cluster", decode_json=True)
33                 status = ret['data']
34                 columns = ('admin-state',
35                            'running-state',
36                            'role'
37                           )
38                 data = (status['admin-state'],
39                         status['running-state'],
40                         status['role']
41                         )
42                 return (columns, data)
43         Why:
44             This module will fill the needed information for authentication.
45             The authentication will be based on keystone.
46         Notes:
47             The object will fill the prefix to the request. So it's not mandatory
48             to write it. This information will be populated from the endpoint of rest frame.
49     """
50     def __init__(self, app_instance):
51         self.instance = app_instance
52         if self.instance._auth_required:
53             self.token = self.instance.auth_ref.auth_token
54             self.auth_ref = self.instance.auth_ref
55             self.url = self.auth_ref.service_catalog.url_for(service_type="restfulapi",
56                                                              service_name="restfulframework",
57                                                              interface=self.instance.interface)
58         else:
59             if 'OS_REST_URL' in os.environ:
60                 self.url = os.environ['OS_REST_URL']
61             else:
62                 raise Exception("OS_REST_URL environment variable missing")
63
64     def get(self, url, data=None, params=None, decode_json=True):
65         return self._operation("get", url, data=data, params=params, decode_json=decode_json)
66
67     def post(self, url, data=None, params=None, decode_json=True):
68         return self._operation("post", url, data=data, params=params, decode_json=decode_json)
69
70     def put(self, url, data=None, params=None, decode_json=True):
71         return self._operation("put", url, data=data, params=params, decode_json=decode_json)
72
73     def patch(self, url, data=None, params=None, decode_json=True):
74         return self._operation("patch", url, data=data, params=params, decode_json=decode_json)
75
76     def delete(self, url, data=None, params=None, decode_json=True):
77         return self._operation("delete", url, data=data, params=params, decode_json=decode_json)
78
79     def _operation(self, oper, url, data=None, params=None, decode_json=True):
80
81         operation = getattr(requests, oper, None)
82
83         if not operation:
84             raise NameError("Operation %s not found" % oper)
85
86         if not url.startswith("http"):
87             url = self.url + '/' + url
88
89         LOG.debug("Working with url %s" % url)
90
91         # Disable request debug logs
92         logging.getLogger("requests").setLevel(logging.WARNING)
93
94         # HACK:Check if the authentication will expire and if so then renew it
95         if self.instance._auth_required and self.auth_ref.will_expire_soon():
96             LOG.debug("Session will expire soon... Renewing token")
97             self.instance._auth_setup_completed = False
98             self.instance._auth_ref = None
99             self.token = self.instance.auth_ref.auth_token
100         else:
101             LOG.debug("Session is solid. Using existing token.")
102
103         # Add security headers
104         arguments = {}
105         headers = {'User-Agent': 'HostCli'}
106
107         if self.instance._auth_required:
108             headers.update({'X-Auth-Token': self.token})
109
110         if data:
111             if isinstance(data, dict):
112                 arguments["json"] = data
113                 headers["Content-Type"] = "application/json"
114             else:
115                 arguments["data"] = data
116                 headers["Content-Type"] = "text/plain"
117
118         arguments["headers"] = headers
119
120         if params:
121             arguments["params"] = params
122
123         ret = operation(url, **arguments)
124
125         if decode_json:
126             ret.raise_for_status()
127             try:
128                 return ret.json()
129             except ValueError:
130                 return {}
131         else:
132             return ret