Class encapsulating a connection to a Splunk server.
This class is used for lower-level REST-based control of Splunk. For most use, you will want to use Context's subclass Service, which provides convenient access to Splunk's various collections and entities.
To use the Context class, create a new Context with a hash of arguments giving the details of the connection, and call the login method on it:
context = Splunk::Context.new(:username => "admin", :password => "changeme").login()
Context#new takes a hash of keyword arguments. The keys it understands are:
:username - log in to Splunk as this user (no default)
:password - password to use when logging in (no default)
:host - Splunk host (e.g. "10.1.2.3") (default: 'localhost')
:port - the Splunk management port (default: 8089)
:protocol - either :https or :http (default: :https)
:namespace - a Namespace object representing the default namespace for this context (default: DefaultNamespace)
:token - a preauthenticated Splunk token (default: nil)
If you specify a token, you need not specify a username or password, nor do you need to call the login method.
Context provides three other important methods:
The default namespace used for requests on this Context.
The namespace must be a Namespace object. If a call to request is made without a namespace, this namespace is used for the request.
Defaults to DefaultNamespace.
Returns: a Namespace object.
The password used to connect.
If a token is provided, this field can be nil.
Returns: a String or nil.
The authentication token on Splunk.
If this Context is not logged in, this is nil. Otherwise it is a String that is passed with each request.
Returns: a String or nil.
# File lib/splunk-sdk-ruby/context.rb, line 72 def initialize(args) @token = args.fetch(:token, nil) @scheme = args.fetch(:scheme, DEFAULT_SCHEME).intern() @host = args.fetch(:host, DEFAULT_HOST) @port = Integer(args.fetch(:port, DEFAULT_PORT)) @username = args.fetch(:username, nil) @password = args.fetch(:password, nil) # Have to use Splunk::namespace() or we will call the # local accessor. @namespace = args.fetch(:namespace, Splunk::namespace(:sharing => "default")) end
Opens a TCP socket to the Splunk HTTP server.
If the scheme field of this Context is :https, this method returns an SSLSocket. If scheme is :http, a TCPSocket is returned. Due to design errors in Ruby's standard library, these two do not share the same method names, so code written for HTTPS will not work for HTTP.
Returns: an SSLSocket or TCPSocket.
# File lib/splunk-sdk-ruby/context.rb, line 162 def connect() socket = TCPSocket.new(@host, @port) if scheme == :https ssl_context = OpenSSL::SSL::SSLContext.new() ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context) ssl_socket.sync_close = true ssl_socket.connect() return ssl_socket else return socket end end
Logs into Splunk and set the token field on this Context.
The login method assumes that the Context has a username and password set. You cannot pass them as arguments to this method. On a successful login, the token field of the Context is set to the token returned by Splunk, and all further requests to the server will send this token.
If this Context already has a token that is not nil, it is already logged in, and this method is a nop.
Raises SplunkHTTPError if there is a problem logging in.
Returns: the Context.
# File lib/splunk-sdk-ruby/context.rb, line 191 def login() if @token # If we're already logged in, this method is a nop. return end response = request(:namespace => Splunk::namespace(:sharing => "default"), :method => :POST, :resource => ["auth", "login"], :query => {}, :headers => {}, :body => {:username=>@username, :password=>@password}) # The response looks like: # <response> # <sessionKey>da950729652f8255c230afe37bdf8b97</sessionKey> # </response> @token = Splunk::text_at_xpath("//sessionKey", response.body) self end
Logs out of Splunk.
This sets the @token attribute to nil.
Returns: the Context.
# File lib/splunk-sdk-ruby/context.rb, line 218 def logout() @token = nil self end
Issues an HTTP(S) request to the Splunk instance.
The request method does not take a URL. Instead, it takes a hash of optional arguments specifying an action in the REST API. This avoids the problem knowing whether a given piece of data is URL encoded or not.
The arguments are:
method: The HTTP method to use (one of :GET, :POST, or :DELETE; default: :GET).
namespace: The namespace to request a resource from Splunk in. Must be a Namespace object. (default: the value of @namespace on this Context)
resource: An array of strings specifying the components of the path to the resource after the namespace. The strings should not be URL encoded, as that will be handled by request. (default: [])
query: A hash containing the values to be encoded as the query (the part following "?") in the URL. Nothing should be URL encoded as request will do the encoding. If you need to pass multiple values for the same key, insert them as an Array as the value of their key into the Hash, and they will be properly encoded as a sequence of entries with the same key. (default: {})
headers: A hash containing the values to be encoded as headers. None should be URL encoded, and the request method will automatically add headers for User-Agent and Splunk authentication for you. Keys must be unique, so the values must be strings, not arrays, unlike for query. (default: {})
body: Either a hash to be encoded as the body of a POST request, or a string to be used as the raw, already encoded body of a POST request. If you pass a hash, you can pass multiple values for the same key by encoding them as an Array, which will be properly set as multiple instances of the same key in the POST body. Nothing in the hash should be URL encoded, as request will handle all such encoding. (default: {})
If Splunk responds with an HTTP code 2xx, the request method returns an HTTP response object (the import methods of which are code, message, and body, and each to enumerate over the response headers). If the HTTP code is not 2xx, request raises a SplunkHTTPError.
Examples:
c = Splunk::connect(username="admin", password="changeme") # Get a list of the indexes in this Splunk instance. c.request(:namespace => Splunk::namespace(), :resource => ["data", "indexes"]) # Create a new index called "my_new_index" c.request(:method => :POST, :resource => ["data", "indexes"], :body => {"name", "my_new_index"})
# File lib/splunk-sdk-ruby/context.rb, line 276 def request(args) method = args.fetch(:method, :GET) scheme = @scheme host = @host port = @port namespace = args.fetch(:namespace, @namespace) resource = args.fetch(:resource, []) query = args.fetch(:query, {}) headers = args.fetch(:headers, {}) body = args.fetch(:body, {}) if method != :GET && method != :POST && method != :DELETE raise ArgumentError.new("Method must be one of :GET, :POST, or " + ":DELETE, found: #{method}") end if scheme && scheme != :http && scheme != :https raise ArgumentError.new("Scheme must be one of :http or :https, " + "found: #{scheme}") end if port && !port.is_a?(Integer) raise ArgumentError.new("Port must be an Integer, found: #{port}") end if !namespace.is_a?(Namespace) raise ArgumentError.new("Namespace must be a Namespace, " + "found: #{namespace}") end # Construct the URL for the request. url = "" url << "#{(scheme || @scheme).to_s}://" url << "#{host || @host}:#{(port || @port).to_s}/" url << (namespace.to_path_fragment() + resource). map {|fragment| URI::encode(fragment)}. join("/") return request_by_url(:url => url, :method => method, :query => query, :headers => headers, :body => body) end
Makes a request to the Splunk server given a prebuilt URL.
Unless you are using a URL that was returned by the Splunk server as part of an Atom feed, you should prefer the request method, which has much clearer semantics.
The request_by_url method takes a hash of arguments. The recognized arguments are:
:url: (a URI object or a String) The URL, including authority, to make a request to.
:method: (:GET, :POST, or :DELETE) The HTTP method to use.
query: A hash containing the values to be encoded as the query (the part following "?") in the URL. Nothing should be URL encoded as request will do the encoding. If you need to pass multiple values for the same key, insert them as an Array as the value of their key into the Hash, and they will be properly encoded as a sequence of entries with the same key. (default: {})
headers: A hash containing the values to be encoded as headers. None should be URL encoded, and the request method will automatically add headers for User-Agent and Splunk authentication for you. Keys must be unique, so the values must be strings, not arrays, unlike for query. (default: {})
body: Either a hash to be encoded as the body of a POST request, or a string to be used as the raw, already encoded body of a POST request. If you pass a hash, you can pass multiple values for the same key by encoding them as an Array, which will be properly set as multiple instances of the same key in the POST body. Nothing in the hash should be URL encoded, as request will handle all such encoding. (default: {})
If Splunk responds with an HTTP code 2xx, the request_by_url method returns an HTTP response object (the import methods of which are code, message, and body, and each to enumerate over the response headers). If the HTTP code is not 2xx, the request_by_url method raises a SplunkHTTPError.
# File lib/splunk-sdk-ruby/context.rb, line 359 def request_by_url(args) url = args.fetch(:url) if url.is_a?(String) url = URI(url) end method = args.fetch(:method, :GET) query = args.fetch(:query, {}) headers = args.fetch(:headers, {}) body = args.fetch(:body, {}) if !query.empty? url.query = URI.encode_www_form(query) end if method == :GET request = Net::HTTP::Get.new(url.request_uri) elsif method == :POST request = Net::HTTP::Post.new(url.request_uri) elsif method == :DELETE request = Net::HTTP::Delete.new(url.request_uri) end # Headers request["User-Agent"] = "splunk-sdk-ruby/#{VERSION}" request["Authorization"] = "Splunk #{@token}" if @token headers.each_entry do |key, value| request[key] = value end # Body if body.is_a?(String) # This case exists only for submitting an event to an index via HTTP. request.body = body else request.body = URI.encode_www_form(body) end # Issue the request. response = Net::HTTP::start( url.hostname, url.port, :use_ssl => url.scheme == 'https', # We don't support certificates. :verify_mode => OpenSSL::SSL::VERIFY_NONE ) do |http| http.request(request) end # Handle any errors. if !response.is_a?(Net::HTTPSuccess) raise SplunkHTTPError.new(response) else return response end end
Restarts this Splunk instance.
The restart method may be called with an optional timeout. If you pass a timeout, restart will wait up to that number of seconds for the server to come back up before returning. If restart did not time out, it leaves the Context logged in when it returns.
If the timeout is, omitted, the restart method returns immediately, and you will have to ascertain if Splunk has come back up yourself, for example with code like:
context = Context.new(...).login() context.restart() Timeout::timeout(timeout) do while !context.server_accepting_connections? || context.server_requires_restart? sleep(0.3) end end
Returns: this Context.
# File lib/splunk-sdk-ruby/context.rb, line 437 def restart(timeout=nil) # Set a message saying that restart is required. Otherwise we have no # way of knowing if Splunk has actually gone down for a restart or not. request(:method => :POST, :namespace => Splunk::namespace(:sharing => "default"), :resource => ["messages"], :body => {"name" => "restart_required", "value" => "Message set by restart method" + " of the Splunk Ruby SDK"}) # Make the actual restart request. request(:method => :POST, :resource => ["server", "control", "restart"]) # Clear our old token, which will no longer work after the restart. logout() # If +timeout+ is +nil+, return immediately. If timeout is a positive # integer, wait for +timeout+ seconds for the server to come back up. if !timeout.nil? Timeout::timeout(timeout) do while !server_accepting_connections? || server_requires_restart? sleep(0.3) end end end # Return the +Context+. self end
Is the Splunk server accepting connections?
Returns true if the Splunk server is up and accepting REST API connections; false otherwise.
# File lib/splunk-sdk-ruby/context.rb, line 474 def server_accepting_connections?() begin # Can't use login, since it has short circuits # when @token != nil on the Context. Instead, make # a request directly. request(:resource => ["data", "indexes"]) rescue Errno::ECONNREFUSED, EOFError, Errno::ECONNRESET return false rescue OpenSSL::SSL::SSLError return false rescue SplunkHTTPError # Splunk is up, because it responded with a proper HTTP error # that our SplunkHTTPError parser understood. return true else # Or the request worked, so we know that Splunk is up. return true end end
Is the Splunk server in a state requiring a restart?
Returns true if the Splunk server is down (equivalent to server_accepting_connections?), or if there is a restart_required message on the server; false otherwise.
# File lib/splunk-sdk-ruby/context.rb, line 501 def server_requires_restart?() begin # We must have two layers of rescue, because the login in the # SplunkHTTPError rescue can also throw Errno::ECONNREFUSED. begin request(:resource => ["messages", "restart_required"]) return true rescue SplunkHTTPError => err if err.code == 401 # The messages endpoint requires authentication. logout() login() return server_requires_restart?() elsif err.code == 404 return false else raise err end end rescue Errno::ECONNREFUSED, EOFError, Errno::ECONNRESET return true end end
Generated with the Darkfish Rdoc Generator 2.