class RedfishClient::Resource

Resource is basic building block of Redfish client and serves as a container for the data that is retrieved from the Redfish service.

When we interact with the Redfish service, resource will wrap the data retrieved from the service API and offer us dot-notation accessors for values stored.

Resource will also load any sub-resource on demand when we access it. For example, if we have a root Redfish resource stored in `root`, accessing `root.SessionService` will automatically fetch the appropriate resource from the API.

In order to reduce the amount of requests being sent to the service, resource can also utilise caching connector. If we would like to get fresh values from the service, {#refresh} call will flush the cache and retrieve fresh data from the remote.

Attributes

headers[R]

Headers, returned from the service when resource has been constructed.

@return [Hash] resource headers

raw[R]

Raw data that has been used to construct resource by either fetching it from the remote API or by being passed-in as a parameter to constructor.

@return [Hash] resource raw data

Public Class Methods

new(connector, oid: nil, raw: nil) click to toggle source

Create new resource.

Resource can be created either by passing in OpenData identifier or supplying the content (hash). In the first case, connector will be used to fetch the resource data. In the second case, resource only wraps the passed-in hash and does no fetching.

@param connector [RedfishClient::Connector] connector that will be used

to fetch the resources

@param oid [String] OpenData id of the resource @param raw [Hash] raw content to populate resource with @raise [NoResource] resource cannot be retrieved from the service

# File lib/redfish_client/resource.rb, line 57
def initialize(connector, oid: nil, raw: nil)
  @connector = connector
  if oid
    initialize_from_service(oid)
  else
    @raw = raw
  end
end

Public Instance Methods

[](attr) click to toggle source

Access resource content.

This function offers a way of accessing resource data in the same way that hash exposes its content.

@param attr [String] key for accessing data @return associated value or `nil` if attr is missing

# File lib/redfish_client/resource.rb, line 94
def [](attr)
  build_resource(raw[attr])
end
delete(field: "@odata.id", path: nil, payload: nil) click to toggle source

Issue a DELETE requests to the endpoint of the resource.

If the resource has no `@odata.id` field, {NoODataId} error will be raised, since deleting non-networked resources makes no sense and probably indicates bug in library consumer.

@return [RedfishClient::Response] response @raise [NoODataId] resource has no OpenData id

# File lib/redfish_client/resource.rb, line 224
def delete(field: "@odata.id", path: nil, payload: nil)
  request(:delete, field, path, payload)
end
dig(*keys) click to toggle source

Safely access nested resource content.

This function is an equivalent of safe navigation operator that can be used with arbitrary keys.

Calling `res.dig(“a”, “b”, “c”)` is equivalent to `res.a&.b&.c` and `res && res[“b”] && res[“b”]`. @params keys [Array<Symbol, String>] sequence of keys to access @return associated value or `nil` if any key is missing

# File lib/redfish_client/resource.rb, line 107
def dig(*keys)
  keys.reduce(self) { |a, k| a.nil? ? nil : a[k] }
end
get(field: "@odata.id", path: nil) click to toggle source

Issue a GET requests to the selected endpoint.

By default, GET request will be sent to the path, stored in `@odata.id` field. Source field can be changed by specifying the `field` parameter when calling this function. Specifying the `path` argument will bypass the field lookup altogether and issue a GET request directly to the selected path.

If the resource has no lookup field, {NoODataId} error will be raised, since posting to non-networked resources makes no sense and probably indicates bug in library consumer.

@param field [String, Symbol] path lookup field @param path [String] path to post to @return [RedfishClient::Response] response @raise [NoODataId] resource has no OpenData id

# File lib/redfish_client/resource.rb, line 174
def get(field: "@odata.id", path: nil)
  request(:get, field, path)
end
key?(name) click to toggle source

Test if resource contains required key.

@param name [String, Symbol] key name to test @return [Boolean] inclusion test result

# File lib/redfish_client/resource.rb, line 115
def key?(name)
  raw.key?(name.to_s)
end
method_missing(symbol, *_args, &_block) click to toggle source

Convenience access for resource data.

Calling `resource.Value` is exactly the same as `resource`.

# File lib/redfish_client/resource.rb, line 122
def method_missing(symbol, *_args, &_block)
  self[symbol.to_s]
end
patch(field: "@odata.id", path: nil, payload: nil) click to toggle source

Issue a PATCH requests to the selected endpoint.

Works exactly the same as the {post} method, but issued a PATCH request to the server.

@param field [String, Symbol] path lookup field @param path [String] path to patch @param payload [Hash<String, >] data to send @return [RedfishClient::Response] response @raise [NoODataId] resource has no OpenData id

# File lib/redfish_client/resource.rb, line 212
def patch(field: "@odata.id", path: nil, payload: nil)
  request(:patch, field, path, payload)
end
post(field: "@odata.id", path: nil, payload: nil) click to toggle source

Issue a POST requests to the selected endpoint.

By default, POST request will be sent to the path, stored in `@odata.id` field. Source field can be changed by specifying the `field` parameter when calling this function. Specifying the `path` argument will bypass the field lookup altogether and POST directly to the requested path.

In order to avoid having to manually serialize data to JSON, this function call takes Hash as a payload and encodes it before sending it to the endpoint.

If the resource has no lookup field, {NoODataId} error will be raised, since posting to non-networked resources makes no sense and probably indicates bug in library consumer.

@param field [String, Symbol] path lookup field @param path [String] path to post to @param payload [Hash<String, >] data to send @return [RedfishClient::Response] response @raise [NoODataId] resource has no OpenData id

# File lib/redfish_client/resource.rb, line 198
def post(field: "@odata.id", path: nil, payload: nil)
  request(:post, field, path, payload)
end
refresh() click to toggle source

Refresh resource content from the API

Caling this method will ensure that the resource data is in sync with the Redfis API, invalidating any caches as necessary.

# File lib/redfish_client/resource.rb, line 232
def refresh
  return unless self["@odata.id"]

  # TODO(@tadeboro): raise more sensible exception if resource cannot be
  # refreshed.
  @connector.reset(self["@odata.id"])
  initialize_from_service(self["@odata.id"])
end
request(method, field, path, payload = nil) click to toggle source

Issue a requests to the selected endpoint.

By default, request will be sent to the path, stored in `@odata.id` field. Source field can be changed by specifying the `field` parameter when calling this function. Specifying the `path` argument will bypass the field lookup altogether and issue a request directly to the selected path.

If the resource has no lookup field, {NoODataId} error will be raised, since posting to non-networked resources makes no sense and probably indicates bug in library consumer.

@param method [Symbol] HTTP method (:get, :post, :patch or :delete) @param field [String, Symbol] path lookup field @param path [String] path to post to @return [RedfishClient::Response] response @raise [NoODataId] resource has no OpenData id

# File lib/redfish_client/resource.rb, line 154
def request(method, field, path, payload = nil)
  @connector.request(method, get_path(field, path), payload)
end
respond_to_missing?(symbol, include_private = false) click to toggle source
Calls superclass method
# File lib/redfish_client/resource.rb, line 126
def respond_to_missing?(symbol, include_private = false)
  key?(symbol.to_s) || super
end
to_s() click to toggle source

Pretty-print the wrapped content.

@return [String] JSON-serialized raw data

# File lib/redfish_client/resource.rb, line 133
def to_s
  JSON.pretty_generate(raw)
end
wait(response, retries: 10, delay: 1) click to toggle source

Wait for the potentially async operation to terminate

Note that this can be safely called on response from non-async operations where the function will return immediately and without making any additional requests to the service.

@param response [RedfishClient::Response] response @param retries [Integer] number of retries @param delay [Integer] number of seconds between retries @return [RedfishClient::Response] final response @raise [Timeout] if the operation did not terminate in time

# File lib/redfish_client/resource.rb, line 77
def wait(response, retries: 10, delay: 1)
  retries.times do |_i|
    return response if response.done?

    sleep(delay)
    response = get(path: response.monitor)
  end
  raise Timeout, "Async operation did not terminate in allotted time"
end

Private Instance Methods

build_hash_resource(data) click to toggle source
# File lib/redfish_client/resource.rb, line 280
def build_hash_resource(data)
  if data.key?("@odata.id")
    Resource.new(@connector, oid: data["@odata.id"])
  else
    Resource.new(@connector, raw: data)
  end
rescue NoResource
  nil
end
build_resource(data) click to toggle source
# File lib/redfish_client/resource.rb, line 270
def build_resource(data)
  return nil if data.nil?

  case data
  when Hash then build_hash_resource(data)
  when Array then data.collect { |d| build_resource(d) }
  else data
  end
end
get_fragment(data, fragment) click to toggle source
# File lib/redfish_client/resource.rb, line 253
def get_fragment(data, fragment)
  # data, /my/0/part -> data["my"][0]["part"]
  parse_fragment_string(fragment).reduce(data) do |acc, c|
    acc[acc.is_a?(Array) ? c.to_i : c]
  end
end
get_path(field, path) click to toggle source
# File lib/redfish_client/resource.rb, line 265
def get_path(field, path)
  raise NoODataId if path.nil? && !key?(field)
  path || raw[field]
end
initialize_from_service(oid) click to toggle source
# File lib/redfish_client/resource.rb, line 243
def initialize_from_service(oid)
  url, fragment = oid.split("#", 2)
  resp = wait(get(path: url))
  raise NoResource unless [200, 201].include?(resp.status)

  @raw = get_fragment(JSON.parse(resp.body), fragment)
  @raw["@odata.id"] = oid
  @headers = resp.headers
end
parse_fragment_string(fragment) click to toggle source
# File lib/redfish_client/resource.rb, line 260
def parse_fragment_string(fragment)
  # /my/0/part -> ["my", "0", "part"]
  fragment ? fragment.split("/").reject { |i| i == "" } : []
end