diff --git a/redfish/main.py b/redfish/main.py index 9b69d1b..094d10a 100644 --- a/redfish/main.py +++ b/redfish/main.py @@ -124,10 +124,9 @@ from future import standard_library standard_library.install_aliases() from builtins import object - - import json -from urllib.parse import urlparse, urljoin +import socket +from urllib.parse import urlparse, urljoin, urlunparse import requests from . import config from . import types @@ -207,13 +206,13 @@ class RedfishConnection(object): "this is insecure and can allow" + " a man in the middle attack") + # Show redfish standard headers + config.logger.debug(self.connection_parameters.headers) + config.logger.debug("Root url : %s", self.connection_parameters.rooturl) self.Root = types.Root(self.connection_parameters.rooturl, self.connection_parameters) - #self.api_url = tortilla.wrap(self.connection_parameters.rooturl, - # debug=TORTILLADEBUG) - #self.root = self.api_url.get(verify=self.connection_parameters.verify_cert) config.logger.info("API Version : %s", self.get_api_version()) mapping.redfish_version = self.get_api_version() @@ -292,9 +291,10 @@ class RedfishConnection(object): url = urljoin(url, "Sessions") # Craft request body and header - requestBody = {"UserName": self.connection_parameters.user_name , "Password": self.connection_parameters.password} + requestBody = {"UserName": self.connection_parameters.user_name, + "Password": self.connection_parameters.password} config.logger.debug(requestBody) - header = {'Content-type': 'application/json'} + headers = self.connection_parameters.headers # ======================================================================= # Tortilla seems not able to provide the header of a post request answer. # However this is required by redfish standard to get X-Auth-Token. @@ -305,24 +305,28 @@ class RedfishConnection(object): # sessions = sessionsUrl.post(verify=self.verify_cert, data=requestBody) auth = requests.post(url, data=json.dumps(requestBody), - headers=header, - verify=self.connection_parameters.verify_cert - ) + headers=headers, + verify=self.connection_parameters.verify_cert) # ======================================================================= # TODO : Manage exception with a class. # ======================================================================= if auth.status_code != 201: try: - answer=auth.json() - except ValueError as e: + answer = auth.json() + except ValueError: answer = "" - raise exception.AuthenticationFailureException("Login request return an invalid status code ", code=auth.status_code, queryAnswer=answer) + raise exception.AuthenticationFailureException( + "Login request return an invalid status code ", + code=auth.status_code, queryAnswer=answer) - self.connection_parameters.auth_token = auth.headers.get("x-auth-token") + self.connection_parameters.auth_token = auth.headers.get( + "x-auth-token") self.connection_parameters.user_uri = auth.headers.get("location") - config.logger.debug("x-auth-token : %s", self.connection_parameters.auth_token) - config.logger.debug("user session : %s", self.connection_parameters.user_uri) + config.logger.debug("x-auth-token : %s", + self.connection_parameters.auth_token) + config.logger.debug("user session : %s", + self.connection_parameters.user_uri) return True def logout(self): @@ -330,13 +334,11 @@ class RedfishConnection(object): url = self.connection_parameters.user_uri # Craft request header - header = {"Content-type": "application/json", - "x-auth-token": self.connection_parameters.auth_token - } + headers = self.connection_parameters.headers - logout = requests.delete(url, headers=header, - verify=self.connection_parameters.verify_cert - ) + logout = requests.delete(url, + headers=headers, + verify=self.connection_parameters.verify_cert) if logout.status_code == 200: config.logger.info("Logout successful") @@ -406,3 +408,17 @@ class ConnectionParameters(object): @user_uri.setter def user_uri(self, user_uri): self.__user_uri = user_uri + + @property + def headers(self): + # Host header is set by request or tortilla + url = urlparse(self.__rooturl) + origin = urlunparse((url.scheme, url.netloc, '', '', '', '')) + headers = {'OData-Version': '4.0', + 'Content-type': 'application/json', + 'Accept': 'application/json', + 'Origin': origin, + 'User-Agent': 'python-redfish'} + if self.auth_token: + headers.update({'x-auth-token': self.auth_token}) + return headers diff --git a/redfish/types.py b/redfish/types.py index 478ab53..28372aa 100644 --- a/redfish/types.py +++ b/redfish/types.py @@ -4,7 +4,6 @@ from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library -standard_library.install_aliases() from builtins import object import pprint @@ -17,6 +16,7 @@ import ssl from . import config from . import mapping from . import exception +standard_library.install_aliases() # Global variable @@ -30,15 +30,12 @@ class Base(object): self.url = url self.api_url = tortilla.wrap(url, debug=config.TORTILLADEBUG) + config.logger.debug(connection_parameters.headers) + try: - if connection_parameters.auth_token is None: - self.data = self.api_url.get( - verify=connection_parameters.verify_cert) - else: - self.data = self.api_url.get( - verify=connection_parameters.verify_cert, - headers={ - 'x-auth-token': connection_parameters.auth_token}) + self.data = self.api_url.get( + verify=connection_parameters.verify_cert, + headers=connection_parameters.headers) except (requests.ConnectionError, ssl.SSLError) as e: # Log and transmit the exception. config.logger.info('Raise a RedfishException to upper level') @@ -119,7 +116,7 @@ class Base(object): config.logger.debug(self.api_url) response = self.api_url.patch( verify=self.connection_parameters.verify_cert, - headers={'x-auth-token': self.connection_parameters.auth_token}, + headers=self.connection_parameters.headers, data=action) return response @@ -317,8 +314,7 @@ class Managers(Base): response = requests.post( reset_url, verify=self.connection_parameters.verify_cert, - headers={'x-auth-token': self.connection_parameters.auth_token, - 'Content-type': 'application/json'}) + headers=self.connection_parameters.headers) # TODO : treat response. return response @@ -357,13 +353,13 @@ class Systems(Base): action['Action'] = 'Reset' action['ResetType'] = 'ForceRestart' - #Debug the url and perform the POST action - #print self.api_url - response = self.api_url.post(verify=self.connection_parameters.verify_cert, - headers={'x-auth-token': self.connection_parameters.auth_token}, - data=action - ) - #TODO : treat response. + # Debug the url and perform the POST action + # print self.api_url + response = self.api_url.post( + verify=self.connection_parameters.verify_cert, + headers=self.connection_parameters.headers, + data=action) + # TODO : treat response. return response def get_bios_version(self): @@ -377,7 +373,8 @@ class Systems(Base): return self.data.Bios.Current.VersionString except: # Returned by mockup. - # Hopefully this kind of discrepencies will be fixed with Redfish 1.0 (August) + # Hopefully this kind of discrepencies will be fixed with + # Redfish 1.0 (August) return self.data.BiosVersion def get_serial_number(self): @@ -391,7 +388,8 @@ class Systems(Base): return self.data.SerialNumber except: # Returned by mockup. - # Hopefully this kind of discrepencies will be fixed with Redfish 1.0 (August) + # Hopefully this kind of discrepencies will be fixed with + # Redfish 1.0 (August) return '' def get_power(self): @@ -413,11 +411,12 @@ class Systems(Base): ''' # perform the POST action - #print self.api_url.url() - response = requests.patch(self.api_url.url(), - verify=self.connection_parameters.verify_cert, - headers={'x-auth-token': self.connection_parameters.auth_token, 'Content-type': 'application/json'}, - data=value) + # print self.api_url.url() + response = requests.patch( + self.api_url.url(), + verify=self.connection_parameters.verify_cert, + headers=self.connection_parameters.headers, + data=value) return response.reason def set_boot_source_override(self, target, enabled): @@ -441,7 +440,9 @@ class Systems(Base): "Continuous" :returns: string -- http response of PATCH request ''' - return self.set_parameter_json('{"Boot": {"BootSourceOverrideTarget": "'+target+'"},{"BootSourceOverrideEnabled" : "'+enabled+'"}}') + return self.set_parameter_json( + '{"Boot": {"BootSourceOverrideTarget": "' + + target + '"},{"BootSourceOverrideEnabled" : "' + enabled + '"}}') class SystemsCollection(BaseCollection): @@ -477,8 +478,11 @@ class EthernetInterfacesCollection(BaseCollection): self.ethernet_interfaces_dict = {} - # Url returned by the mock up is wrong /redfish/v1/Managers/EthernetInterfaces/1 returns a 404. --> this is not true anymore (2016/01/03) - # The correct one should be /redfish/v1/Managers/1/EthernetInterfaces/1 --> correct by mockup return invalid content (not json) + # Url returned by the mock up is wrong + # /redfish/v1/Managers/EthernetInterfaces/1 returns a 404. + # --> this is not true anymore (2016/01/03) + # The correct one should be /redfish/v1/Managers/1/EthernetInterfaces/1 + # --> correct by mockup return invalid content (not json) # Check more than 1 hour for this bug.... grrr.... for link in self.links: index = re.search(r'EthernetInterfaces/(\w+)', link)