class RedfishClient::Connector
Connector serves as a low-level wrapper around HTTP calls that are used to retrieve data from the service API. It abstracts away implementation details such as sending the proper headers in request, which do not change between resource fetches.
Library users should treat this class as an implementation detail and use higer-level {RedfishClient::Resource} instead.
Constants
- BASIC_AUTH_HEADER
Basic and token authentication header names
- DEFAULT_HEADERS
Default headers, as required by Redfish spec redfish.dmtf.org/schemas/DSP0266_1.4.0.html#request-headers
- LOCATION_HEADER
- TOKEN_AUTH_HEADER
Public Class Methods
Create new connector.
By default, connector performs no caching. If caching is desired, Hash should be used as a cache implementation.
It is also possible to pass in custom caching class. Instances of that class should respond to the following four methods:
1. `[](key)` - Used to access cached content and should return `nil` if the key has no associated value. 2. `[]=(key, value)` - Cache `value` under the `key` 3. `clear` - Clear the complete cache. 4. `delete(key)` - Invalidate cache entry associated with `key`.
@param url [String] base url of the Redfish service @param verify [Boolean] verify SSL certificate of the service @param cache [Object] cache backend
# File lib/redfish_client/connector.rb, line 50 def initialize(url, verify: true, cache: nil) @url = url @headers = DEFAULT_HEADERS.dup middlewares = Excon.defaults[:middlewares] + [Excon::Middleware::RedirectFollower] @connection = Excon.new(@url, ssl_verify_peer: verify, middlewares: middlewares) @cache = cache || NilHash.new end
Public Instance Methods
Add HTTP headers to the requests made by the connector.
@param headers [Hash<String, String>] headers to be added
# File lib/redfish_client/connector.rb, line 64 def add_headers(headers) @headers.merge!(headers) end
Issue DELETE requests to the service.
@param path [String] path to the resource, relative to the base @return [Response] response object
# File lib/redfish_client/connector.rb, line 126 def delete(path) request(:delete, path) end
Issue GET request to service.
This method will first try to return cached response if available. If cache does not contain entry for this request, data will be fetched from remote and then cached, but only if the response has an OK (200) status.
@param path [String] path to the resource, relative to the base url @return [Response] response object
# File lib/redfish_client/connector.rb, line 100 def get(path) request(:get, path) end
Authenticate against the service.
Calling this method will try to authenticate against API using credentials provided by #{set_auth_info} call. If authentication fails, # {AuthError} will be raised.
@raise [AuthError] if credentials are invalid
# File lib/redfish_client/connector.rb, line 169 def login @session_path ? session_login : basic_login end
Sign out of the service.
# File lib/redfish_client/connector.rb, line 174 def logout # We bypass request here because we do not want any retries on 401 # when doing logout. if @session_oid params = prepare_request_params(:delete, @session_oid) @connection.request(params) @session_oid = nil end remove_headers([BASIC_AUTH_HEADER, TOKEN_AUTH_HEADER]) end
Issue PATCH requests to the service.
@param path [String] path to the resource, relative to the base @param data [Hash] data to be sent over the socket @return [Response] response object
# File lib/redfish_client/connector.rb, line 118 def patch(path, data = nil) request(:patch, path, data) end
Issue POST requests to the service.
@param path [String] path to the resource, relative to the base @param data [Hash] data to be sent over the socket, JSON encoded @return [Response] response object
# File lib/redfish_client/connector.rb, line 109 def post(path, data = nil) request(:post, path, data) end
Remove HTTP headers from requests made by the connector.
Headers that are not currently set are silently ignored and no error is raised.
@param headers [List<String>] headers to remove
# File lib/redfish_client/connector.rb, line 74 def remove_headers(headers) headers.each { |h| @headers.delete(h) } end
Issue requests to the service.
@param mathod [Symbol] HTTP method (:get, :post, :patch or :delete) @param path [String] path to the resource, relative to the base @param data [Hash] data to be sent over the socket @return [Response] response object
# File lib/redfish_client/connector.rb, line 84 def request(method, path, data = nil) return @cache[path] if method == :get && @cache[path] do_request(method, path, data).tap do |r| @cache[path] = r if method == :get && r.status == 200 end end
Clear the cached responses.
If path is passed as a parameter, only one cache entry gets invalidated, else complete cache gets invalidated.
Next GET request will repopulate the cache.
@param path [String] path to invalidate
# File lib/redfish_client/connector.rb, line 138 def reset(path = nil) path.nil? ? @cache.clear : @cache.delete(path) end
Set authentication-related variables.
Last parameter controls the kind of login connector will perform. If session_path is `nil`, basic authentication will be used, otherwise connector will use session-based authentication.
Note that actual login is done lazily. If you need to check for credential validity, call #{login} method.
@param username [String] API username @param password [String] API password @param auth_test_path [String] API path to test credential's validity @param session_path [String, nil] API session path
# File lib/redfish_client/connector.rb, line 155 def set_auth_info(username, password, auth_test_path, session_path = nil) @username = username @password = password @auth_test_path = auth_test_path @session_path = session_path end
Private Instance Methods
# File lib/redfish_client/connector.rb, line 251 def auth_valid? # We bypass request here because we do not want any retries on 401 # when checking authentication headers. reset(@auth_test_path) # Do not want to see cached response params = prepare_request_params(:get, @auth_test_path) @connection.request(params).status == 200 end
# File lib/redfish_client/connector.rb, line 238 def basic_login payload = Base64.encode64("#{@username}:#{@password}").strip add_headers(BASIC_AUTH_HEADER => "Basic #{payload}") return if auth_valid? remove_headers([BASIC_AUTH_HEADER]) raise_invalid_auth_error end
# File lib/redfish_client/connector.rb, line 187 def do_request(method, path, data) params = prepare_request_params(method, path, data) r = @connection.request(params) if r.status == 401 login r = @connection.request(params) end Response.new(r.status, downcase_headers(r.data[:headers]), r.data[:body]) end
# File lib/redfish_client/connector.rb, line 197 def downcase_headers(headers) headers.each_with_object({}) { |(k, v), obj| obj[k.downcase] = v } end
# File lib/redfish_client/connector.rb, line 201 def prepare_request_params(method, path, data = nil) params = { method: method, path: path } if data params[:body] = data.to_json params[:headers] = @headers.merge("Content-Type" => "application/json") else params[:headers] = @headers end params end
# File lib/redfish_client/connector.rb, line 247 def raise_invalid_auth_error raise AuthError, "Invalid credentials" end
# File lib/redfish_client/connector.rb, line 228 def save_session_oid!(body, headers) @session_oid = body["@odata.id"] if body.key?("@odata.id") return if @session_oid return unless headers.key?(LOCATION_HEADER) location = URI.parse(headers[LOCATION_HEADER]) @session_oid = [location.path, location.query].compact.join("?") end
# File lib/redfish_client/connector.rb, line 212 def session_login # We bypass request here because we do not want any retries on 401 # when doing login. params = prepare_request_params(:post, @session_path, "UserName" => @username, "Password" => @password) r = @connection.request(params) raise_invalid_auth_error unless r.status == 201 body = JSON.parse(r.data[:body]) headers = r.data[:headers] add_headers(TOKEN_AUTH_HEADER => headers[TOKEN_AUTH_HEADER]) save_session_oid!(body, headers) end