迁移原来 LMR 开发的日志查询
parent
51e90ac73b
commit
59aa831764
@ -0,0 +1,11 @@
|
||||
# OS X
|
||||
.DS_Store
|
||||
|
||||
# Generated documentation
|
||||
apidocs/
|
||||
|
||||
# Generated code coverage report
|
||||
coverage/
|
||||
|
||||
# Local settings
|
||||
*.local.php
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Intercepts failed attempts to load classes of the form 'Splunk_*'
|
||||
* and automatically includes the appropriate PHP file for the class.
|
||||
*/
|
||||
function Splunk_autoload($className)
|
||||
{
|
||||
if (substr_compare($className, 'Splunk_', 0, strlen('Splunk_')) != 0)
|
||||
return false;
|
||||
$file = str_replace('_', '/', $className);
|
||||
return include dirname(__FILE__) . "/$file.php";
|
||||
}
|
||||
|
||||
spl_autoload_register('Splunk_autoload');
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.2.11') < 0)
|
||||
die('The Splunk SDK for PHP requires PHP 5.2.11 or later.');
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to access a Splunk entity with a name
|
||||
* that matches multiple entities in the current (non-exact) namespace.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_AmbiguousEntityNameException extends RuntimeException
|
||||
{
|
||||
/** @internal */
|
||||
public function __construct($name)
|
||||
{
|
||||
parent::__construct(
|
||||
"Multiple entities exist with name '{$name}'. " .
|
||||
"Specify an exact namespace to disambiguate.");
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains utilities for parsing Atom feeds received from the Splunk REST API.
|
||||
*
|
||||
* @package Splunk
|
||||
* @internal
|
||||
*/
|
||||
class Splunk_AtomFeed
|
||||
{
|
||||
/** Name of the 's' namespace in Splunk Atom feeds. */
|
||||
const NS_S = 'http://dev.splunk.com/ns/rest';
|
||||
|
||||
/**
|
||||
* Parses and returns the value inside the specified XML element.
|
||||
*
|
||||
* @param SimpleXMLElement $containerXml
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parseValueInside($containerXml)
|
||||
{
|
||||
$dictValue = $containerXml->children(Splunk_AtomFeed::NS_S)->dict;
|
||||
$listValue = $containerXml->children(Splunk_AtomFeed::NS_S)->list;
|
||||
|
||||
if (Splunk_XmlUtil::elementExists($dictValue))
|
||||
{
|
||||
return Splunk_AtomFeed::parseDict($dictValue);
|
||||
}
|
||||
else if (Splunk_XmlUtil::elementExists($listValue))
|
||||
{
|
||||
return Splunk_AtomFeed::parseList($listValue);
|
||||
}
|
||||
else // value is scalar
|
||||
{
|
||||
return Splunk_XmlUtil::getTextContent($containerXml);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Example of $dictXml:
|
||||
*
|
||||
* <s:dict>
|
||||
* <s:key name="k1">v1</s:key>
|
||||
* <s:key name="k2">v2</s:key>
|
||||
* </s:dict>
|
||||
*/
|
||||
private static function parseDict($dictXml)
|
||||
{
|
||||
$dict = array();
|
||||
foreach ($dictXml->children(Splunk_AtomFeed::NS_S)->key as $keyXml)
|
||||
{
|
||||
$key = Splunk_XmlUtil::getAttributeValue($keyXml, 'name');
|
||||
$value = Splunk_AtomFeed::parseValueInside($keyXml);
|
||||
|
||||
$dict[$key] = $value;
|
||||
}
|
||||
return $dict;
|
||||
}
|
||||
|
||||
/*
|
||||
* Example of $listXml:
|
||||
*
|
||||
* <s:list>
|
||||
* <s:item>e1</s:item>
|
||||
* <s:item>e2</s:item>
|
||||
* </s:list>
|
||||
*/
|
||||
private static function parseList($listXml)
|
||||
{
|
||||
$list = array();
|
||||
foreach ($listXml->children(Splunk_AtomFeed::NS_S)->item as $itemXml)
|
||||
$list[] = Splunk_AtomFeed::parseValueInside($itemXml);
|
||||
return $list;
|
||||
}
|
||||
}
|
@ -0,0 +1,313 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a collection of entities accessible through Splunk's REST API.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Collection extends Splunk_Endpoint
|
||||
{
|
||||
private $entitySubclass;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param Splunk_Service $service
|
||||
* @param string $path
|
||||
* @param string $entitySubclass (optional) name of the entity subclass
|
||||
* that this collection's children will
|
||||
* be instantiated with.
|
||||
*/
|
||||
public function __construct($service, $path, $entitySubclass='Splunk_Entity')
|
||||
{
|
||||
parent::__construct($service, $path);
|
||||
$this->entitySubclass = $entitySubclass;
|
||||
}
|
||||
|
||||
// === Accessors ===
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
*/
|
||||
protected function getSearchNamespace()
|
||||
{
|
||||
// (The namespace cannot presently be overridden on a per-collection basis.)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// === Operations ===
|
||||
|
||||
// NOTE: This method isn't called 'list' only because PHP treats 'list' as a
|
||||
// pseudo-keyword and gets confused when it's used as a method name.
|
||||
/**
|
||||
* Lists this collection's entities, returning a list of loaded entities.
|
||||
*
|
||||
* By default, all items in the collection are returned. For large
|
||||
* collections, it is advisable to fetch items using multiple calls with
|
||||
* the paging options (i.e. 'offset' and 'count').
|
||||
*
|
||||
* @param array $args (optional) {<br/>
|
||||
* **namespace**: (optional) {Splunk_Namespace} The namespace in which
|
||||
* to list entities. Defaults to the service's namespace.<br/>
|
||||
*
|
||||
* **count**: (optional) The maximum number of items to return,
|
||||
* or -1 to return as many as possible.
|
||||
* Defaults to returning as many as possible.<br/>
|
||||
* **offset**: (optional) The offset of the first item to return.
|
||||
* Defaults to 0.<br/>
|
||||
*
|
||||
* **search**: (optional) The search expression to filter responses
|
||||
* with. For example, "foo" matches any object that has
|
||||
* "foo" in a substring of a field. Similarly the
|
||||
* expression "field_name=field_value" matches only objects
|
||||
* that have a "field_name" field with the value
|
||||
* "field_value".<br/>
|
||||
* **sort_dir**: (optional) The direction to sort returned items.<br/>
|
||||
* Valid values:<br/>
|
||||
* - "asc": Sort in ascending order.<br/>
|
||||
* - "desc": Sort in descending order.<br/>
|
||||
* Defaults to "asc".<br/>
|
||||
* **sort_key**: (optional) The field to use for sorting.
|
||||
* Defaults to "name".<br/>
|
||||
* **sort_mode**: (optional) The sorting algorithm to use. Valid values:<br/>
|
||||
* - "auto": If all values of the field are numbers,
|
||||
* sort numerically. Otherwise, sort
|
||||
* alphabetically.<br/>
|
||||
* - "alpha": Sort alphabetically.<br/>
|
||||
* - "alpha_case": Sort alphabetically, case-sensitive.<br/>
|
||||
* - "num": Sort numerically.<br/>
|
||||
* Defaults to "auto".<br/>
|
||||
* }
|
||||
* @return array the entities in the listing.
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function items($args=array())
|
||||
{
|
||||
$args = array_merge(array(
|
||||
'count' => -1,
|
||||
), $args);
|
||||
|
||||
if ($args['count'] <= 0 && $args['count'] != -1)
|
||||
throw new InvalidArgumentException(
|
||||
'Count must be positive or -1 (infinity).');
|
||||
|
||||
if ($args['count'] == -1)
|
||||
$args['count'] = 0; // infinity value for the REST API
|
||||
|
||||
$response = $this->sendGet('', $args);
|
||||
return $this->loadEntitiesFromResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of entities from the given response.
|
||||
*
|
||||
* @param $response
|
||||
* @return array array of Splunk_Entry.
|
||||
*/
|
||||
private function loadEntitiesFromResponse($response)
|
||||
{
|
||||
$xml = new SimpleXMLElement($response->body);
|
||||
|
||||
$entities = array();
|
||||
foreach ($xml->entry as $entry)
|
||||
{
|
||||
$entities[] = $this->loadEntityFromEntry($entry);
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an entity from the given entry element.
|
||||
*
|
||||
* @param SimpleXMLElement $entry an <entry> element.
|
||||
* @return Splunk_Entry
|
||||
*/
|
||||
private function loadEntityFromEntry($entry)
|
||||
{
|
||||
return new $this->entitySubclass(
|
||||
$this->service,
|
||||
$this->getEntityPath($entry->title),
|
||||
$entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique entity with the specified name in this collection.
|
||||
*
|
||||
* @param string $name The name of the entity to search for.
|
||||
* @param Splunk_Namespace|NULL $namespace
|
||||
* (optional) {Splunk_Namespace} The namespace in which
|
||||
* to search. Defaults to the service's namespace.
|
||||
* @return Splunk_Entity
|
||||
* @throws Splunk_NoSuchEntityException
|
||||
* If no such entity exists.
|
||||
* @throws Splunk_AmbiguousEntityNameException
|
||||
* If multiple entities with the specified name
|
||||
* exist in the specified namespace.
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function get($name, $namespace=NULL)
|
||||
{
|
||||
$this->checkName($name);
|
||||
$this->checkNamespace($namespace);
|
||||
|
||||
try
|
||||
{
|
||||
$response = $this->sendGet($this->getEntityRelativePath($name), array(
|
||||
'namespace' => $namespace,
|
||||
'count' => 0,
|
||||
));
|
||||
$entities = $this->loadEntitiesFromResponse($response);
|
||||
}
|
||||
catch (Splunk_HttpException $e)
|
||||
{
|
||||
if ($e->getResponse()->status == 404)
|
||||
$entities = array();
|
||||
else
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (count($entities) == 0)
|
||||
{
|
||||
throw new Splunk_NoSuchEntityException($name);
|
||||
}
|
||||
else if (count($entities) == 1)
|
||||
{
|
||||
return $entities[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Splunk_AmbiguousEntityNameException($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the unique entity with the specified name in this
|
||||
* collection. Loading of the entity is deferred until its first use.
|
||||
*
|
||||
* @param string $name The name of the entity to search for.
|
||||
* @param Splunk_Namespace|NULL $namespace
|
||||
* (optional) {Splunk_Namespace} The namespace in which
|
||||
* to search. Defaults to the service's namespace.
|
||||
* @return Splunk_Entity
|
||||
*/
|
||||
public function getReference($name, $namespace=NULL)
|
||||
{
|
||||
$this->checkName($name);
|
||||
$this->checkNamespace($namespace);
|
||||
|
||||
return new $this->entitySubclass(
|
||||
$this->service,
|
||||
$this->getEntityPath($name),
|
||||
NULL,
|
||||
$namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new entity in this collection.
|
||||
*
|
||||
* @param string $name The name of the entity to create.
|
||||
* @param array $args (optional) Entity-specific creation arguments,
|
||||
* merged with {<br/>
|
||||
* **namespace**: (optional) {Splunk_Namespace} The namespace in which
|
||||
* to create the entity. Defaults to the service's
|
||||
* namespace.<br/>
|
||||
* }
|
||||
* @return Splunk_Entity
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function create($name, $args=array())
|
||||
{
|
||||
$this->checkName($name);
|
||||
|
||||
$args = array_merge(array(
|
||||
'name' => $name,
|
||||
), $args);
|
||||
|
||||
$response = $this->sendPost('', $args);
|
||||
if ($response->body === '')
|
||||
{
|
||||
// This endpoint doesn't return the content of the new entity.
|
||||
return $this->getReference($name);
|
||||
}
|
||||
else
|
||||
{
|
||||
$xml = new SimpleXMLElement($response->body);
|
||||
return $this->loadEntityFromEntry($xml->entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entity from this collection.
|
||||
*
|
||||
* @param string $name The name of the entity to delete.
|
||||
* @param array $args (optional) Entity-specific deletion arguments,
|
||||
* merged with {<br/>
|
||||
* **namespace**: (optional) {Splunk_Namespace} The namespace in which
|
||||
* to find the entity. Defaults to the service's
|
||||
* namespace.<br/>
|
||||
* }
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function delete($name, $args=array())
|
||||
{
|
||||
$this->checkName($name);
|
||||
|
||||
$this->sendDelete($this->getEntityRelativePath($name), $args);
|
||||
}
|
||||
|
||||
// === Utility ===
|
||||
|
||||
/**
|
||||
* Returns the absolute path of the child entity with the specified name.
|
||||
*/
|
||||
private function getEntityPath($name)
|
||||
{
|
||||
return $this->path . $this->getEntityRelativePath($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative path of the child entity with the specified name.
|
||||
*/
|
||||
private function getEntityRelativePath($name)
|
||||
{
|
||||
return urlencode($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the specified name is not NULL or empty.
|
||||
*/
|
||||
protected function checkName($name)
|
||||
{
|
||||
if ($name === NULL || $name === '')
|
||||
throw new InvalidArgumentException('Invalid empty name.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the specified namespace is a Splunk_Namespace if it is
|
||||
* not NULL.
|
||||
*/
|
||||
protected function checkNamespace($namespace)
|
||||
{
|
||||
// (It's not uncommon to attempt to pass an args dictionary after
|
||||
// the $name argument, so perform an explicit type check to make sure
|
||||
// the caller isn't trying to do this.)
|
||||
if ($namespace !== NULL && !($namespace instanceof Splunk_Namespace))
|
||||
throw new InvalidArgumentException(
|
||||
'Namespace must be NULL or a Splunk_Namespace.');
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown when unable to connect to a Splunk server.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_ConnectException extends Splunk_IOException
|
||||
{
|
||||
/** @internal */
|
||||
public function __construct($message=NULL, $code=0)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
}
|
@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enables clients to issue HTTP requests to a Splunk server.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Context
|
||||
{
|
||||
private $username;
|
||||
private $password;
|
||||
private $token;
|
||||
private $host;
|
||||
private $port;
|
||||
private $scheme;
|
||||
private $namespace;
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* Constructs a new context with the specified parameters.
|
||||
*
|
||||
* @param array $args {<br/>
|
||||
* **username**: (optional) The username to login with. Defaults to
|
||||
* "admin".<br/>
|
||||
* **password**: (optional) The password to login with. Defaults to
|
||||
* "changeme".<br/>
|
||||
* **token**: (optional) The authentication token to use. If provided,
|
||||
* the username and password are ignored and there is no
|
||||
* need to call login(). In the format "Splunk SESSION_KEY".
|
||||
* <br/>
|
||||
* **host**: (optional) The hostname of the Splunk server. Defaults to
|
||||
* "localhost".<br/>
|
||||
* **port**: (optional) The port of the Splunk server. Defaults to
|
||||
* 8089.<br/>
|
||||
* **scheme**: (optional) The scheme to use: either "http" or "https".
|
||||
* Defaults to "https".<br/>
|
||||
* **namespace**: (optional) Namespace that all object lookups will
|
||||
* occur in by default. Defaults to
|
||||
* `Splunk_Namespace::createDefault()`.<br/>
|
||||
* **http**: (optional) An Http object that will be used for
|
||||
* performing HTTP requests. This is intended for testing
|
||||
* only.<br/>
|
||||
* }
|
||||
*/
|
||||
public function __construct($args=array())
|
||||
{
|
||||
$args = array_merge(array(
|
||||
'username' => 'admin',
|
||||
'password' => 'changeme',
|
||||
'token' => NULL,
|
||||
'host' => 'localhost',
|
||||
'port' => 8089,
|
||||
'scheme' => 'https',
|
||||
'namespace' => Splunk_Namespace::createDefault(),
|
||||
'http' => new Splunk_Http(),
|
||||
), $args);
|
||||
|
||||
$this->username = $args['username'];
|
||||
$this->password = $args['password'];
|
||||
$this->token = $args['token'];
|
||||
$this->host = $args['host'];
|
||||
$this->port = $args['port'];
|
||||
$this->scheme = $args['scheme'];
|
||||
$this->namespace = $args['namespace'];
|
||||
$this->http = $args['http'];
|
||||
}
|
||||
|
||||
// === Operations ===
|
||||
|
||||
/**
|
||||
* Authenticates to the Splunk server.
|
||||
*/
|
||||
public function login()
|
||||
{
|
||||
$response = $this->http->post($this->url('/services/auth/login'), array(
|
||||
'username' => $this->username,
|
||||
'password' => $this->password,
|
||||
));
|
||||
|
||||
$sessionKey = Splunk_XmlUtil::getTextContentAtXpath(
|
||||
new SimpleXMLElement($response->body),
|
||||
'/response/sessionKey');
|
||||
|
||||
$this->token = "Splunk {$sessionKey}";
|
||||
}
|
||||
|
||||
// === HTTP ===
|
||||
|
||||
/**
|
||||
* Sends an HTTP GET request to the endpoint at the specified path.
|
||||
*
|
||||
* @param string $path relative or absolute URL path.
|
||||
* @param array $args (optional) query parameters, merged with {<br/>
|
||||
* **namespace**: (optional) namespace to use, or NULL to use
|
||||
* this context's default namespace.<br/>
|
||||
* }
|
||||
* @return Splunk_HttpResponse
|
||||
* @throws Splunk_IOException
|
||||
* @see Splunk_Http::get()
|
||||
*/
|
||||
public function sendGet($path, $args=array())
|
||||
{
|
||||
return $this->sendSimpleRequest('get', $path, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP POST request to the endpoint at the specified path.
|
||||
*
|
||||
* @param string $path relative or absolute URL path.
|
||||
* @param array $args (optional) form parameters to send in the
|
||||
* request body, merged with {<br/>
|
||||
* **namespace**: (optional) namespace to use, or NULL to use
|
||||
* this context's default namespace.<br/>
|
||||
* }
|
||||
* @return Splunk_HttpResponse
|
||||
* @throws Splunk_IOException
|
||||
* @see Splunk_Http::post()
|
||||
*/
|
||||
public function sendPost($path, $args=array())
|
||||
{
|
||||
return $this->sendSimpleRequest('post', $path, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP DELETE request to the endpoint at the specified path.
|
||||
*
|
||||
* @param string $path relative or absolute URL path.
|
||||
* @param array $args (optional) query parameters, merged with {<br/>
|
||||
* **namespace**: (optional) namespace to use, or NULL to use
|
||||
* this context's default namespace.<br/>
|
||||
* }
|
||||
* @return Splunk_HttpResponse
|
||||
* @throws Splunk_IOException
|
||||
* @see Splunk_Http::delete()
|
||||
*/
|
||||
public function sendDelete($path, $args=array())
|
||||
{
|
||||
return $this->sendSimpleRequest('delete', $path, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a simple HTTP request to the endpoint at the specified path.
|
||||
*/
|
||||
private function sendSimpleRequest($method, $path, $args)
|
||||
{
|
||||
list($params, $namespace) =
|
||||
Splunk_Util::extractArgument($args, 'namespace', NULL);
|
||||
|
||||
return $this->http->$method(
|
||||
$this->url($path, $namespace),
|
||||
$params,
|
||||
$this->getRequestHeaders());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP request to the endpoint at the specified path.
|
||||
*
|
||||
* @param string $method the HTTP method (ex: 'GET' or 'POST').
|
||||
* @param string $path relative or absolute URL path.
|
||||
* @param array $requestHeaders (optional) dictionary of header names and
|
||||
* values.
|
||||
* @param string $requestBody (optional) content to send in the request.
|
||||
* @param array $args (optional) query parameters, merged with
|
||||
* {<br/>
|
||||
* **namespace**: (optional) namespace to use, or NULL to use
|
||||
* this context's default namespace.<br/>
|
||||
* }
|
||||
* @return Splunk_HttpResponse
|
||||
* @throws Splunk_IOException
|
||||
* @see Splunk_Http::request()
|
||||
*/
|
||||
public function sendRequest(
|
||||
$method, $path, $requestHeaders=array(), $requestBody='', $args=array())
|
||||
{
|
||||
list($params, $namespace) =
|
||||
Splunk_Util::extractArgument($args, 'namespace', NULL);
|
||||
|
||||
$url = $this->url($path, $namespace);
|
||||
$fullUrl = (count($params) == 0)
|
||||
? $url
|
||||
: $url . '?' . http_build_query($params);
|
||||
|
||||
$requestHeaders = array_merge(
|
||||
$this->getRequestHeaders(),
|
||||
$requestHeaders);
|
||||
|
||||
return $this->http->request(
|
||||
$method,
|
||||
$fullUrl,
|
||||
$requestHeaders,
|
||||
$requestBody);
|
||||
}
|
||||
|
||||
/** Returns the standard headers to send on each HTTP request. */
|
||||
private function getRequestHeaders()
|
||||
{
|
||||
return array(
|
||||
'Authorization' => $this->token,
|
||||
);
|
||||
}
|
||||
|
||||
// === Accessors ===
|
||||
|
||||
/**
|
||||
* Gets the default namespace for collection and entity operations.
|
||||
*
|
||||
* @return Splunk_Namespace The default namespace that will be used
|
||||
* to perform collection and entity operations
|
||||
* when none is explicitly specified.
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token used to authenticate HTTP requests after logging in.
|
||||
*
|
||||
* @return string The token used to authenticate HTTP requests
|
||||
* after logging in.
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hostname of the Splunk server.
|
||||
*
|
||||
* @return string The hostname of the Splunk server.
|
||||
*/
|
||||
public function getHost()
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the port of the Splunk server.
|
||||
*
|
||||
* @return string The port of the Splunk server.
|
||||
*/
|
||||
public function getPort()
|
||||
{
|
||||
return $this->port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scheme to use.
|
||||
*
|
||||
* @return string The scheme to use: either "http" or "https".
|
||||
*/
|
||||
public function getScheme()
|
||||
{
|
||||
return $this->scheme;
|
||||
}
|
||||
|
||||
// === Utility ===
|
||||
|
||||
/**
|
||||
* Returns the absolute URL.
|
||||
*
|
||||
* @param string $path Relative or absolute URL path.
|
||||
* @param Splunk_Namespace|NULL $namespace
|
||||
* @return string Absolute URL.
|
||||
*/
|
||||
private function url($path, $namespace=NULL)
|
||||
{
|
||||
return "{$this->scheme}://{$this->host}:{$this->port}{$this->abspath($path, $namespace)}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL path.
|
||||
*
|
||||
* @param string $path Relative or absolute URL path.
|
||||
* @param Splunk_Namespace|NULL $namespace
|
||||
* @return string Absolute URL path.
|
||||
*/
|
||||
private function abspath($path, $namespace=NULL)
|
||||
{
|
||||
if ((strlen($path) >= 1) && ($path[0] == '/'))
|
||||
return $path;
|
||||
if ($namespace === NULL)
|
||||
$namespace = $this->namespace;
|
||||
|
||||
return $namespace->getPathPrefix() . $path;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a single endpoint in the Splunk REST API.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
abstract class Splunk_Endpoint
|
||||
{
|
||||
protected $service;
|
||||
protected $path;
|
||||
|
||||
/** @internal */
|
||||
public function __construct($service, $path)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
// === Accessors ===
|
||||
|
||||
/**
|
||||
* Returns the namespace in which this endpoint resides, or NULL to use
|
||||
* the context's default namespace.
|
||||
*
|
||||
* @return Splunk_Namespace|NULL The namespace in which this endpoint
|
||||
* resides, or NULL to use the context's
|
||||
* default namespace.
|
||||
* Possibly a non-exact namespace.
|
||||
*/
|
||||
protected abstract function getSearchNamespace();
|
||||
|
||||
// === HTTP ===
|
||||
|
||||
/**
|
||||
* Sends an HTTP GET request relative to this endpoint.
|
||||
*
|
||||
* @param string $relativePath relative URL path.
|
||||
* @param array $args (optional) query parameters, merged with {<br/>
|
||||
* **namespace**: (optional) namespace to use, or NULL to use
|
||||
* the context's default namespace.<br/>
|
||||
* }
|
||||
* @return Splunk_HttpResponse
|
||||
* @throws Splunk_IOException
|
||||
* @see Splunk_Http::get()
|
||||
*/
|
||||
public function sendGet($relativePath, $args=array())
|
||||
{
|
||||
return $this->sendSimpleRequest('sendGet', $relativePath, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP POST request relative to this endpoint.
|
||||
*
|
||||
* @param string $relativePath relative URL path.
|
||||
* @param array $args (optional) form parameters to send in the request
|
||||
* body, merged with {<br/>
|
||||
* **namespace**: (optional) namespace to use, or NULL to use
|
||||
* the context's default namespace.<br/>
|
||||
* }
|
||||
* @return Splunk_HttpResponse
|
||||
* @throws Splunk_IOException
|
||||
* @see Splunk_Http::post()
|
||||
*/
|
||||
public function sendPost($relativePath, $args=array())
|
||||
{
|
||||
return $this->sendSimpleRequest('sendPost', $relativePath, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP DELETE request relative to this endpoint.
|
||||
*
|
||||
* @param string $relativePath relative URL path.
|
||||
* @param array $args (optional) query parameters, merged with {<br/>
|
||||
* **namespace**: (optional) namespace to use, or NULL to use
|
||||
* the context's default namespace.<br/>
|
||||
* }
|
||||
* @return Splunk_HttpResponse
|
||||
* @throws Splunk_IOException
|
||||
* @see Splunk_Http::delete()
|
||||
*/
|
||||
public function sendDelete($relativePath, $args=array())
|
||||
{
|
||||
return $this->sendSimpleRequest('sendDelete', $relativePath, $args);
|
||||
}
|
||||
|
||||
/** Sends a simple request relative to this endpoint. */
|
||||
private function sendSimpleRequest($method, $relativePath, $args=array())
|
||||
{
|
||||
$args = array_merge(array(
|
||||
'namespace' => $this->getSearchNamespace(),
|
||||
), $args);
|
||||
|
||||
return $this->service->$method("{$this->path}{$relativePath}", $args);
|
||||
}
|
||||
}
|
@ -0,0 +1,298 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents an entity accessible through Splunk's REST API.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Entity extends Splunk_Endpoint implements ArrayAccess
|
||||
{
|
||||
private $loaded = FALSE;
|
||||
private $entry;
|
||||
private $namespace;
|
||||
private $content;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param Splunk_Service $service
|
||||
* @param string $path
|
||||
* @param SimpleXMLElement|NULL $entry
|
||||
* (optional) The <entry> for this
|
||||
* entity, as received from the REST API.
|
||||
* If omitted, will be loaded on demand.
|
||||
* @param Splunk_Namespace|NULL $namespace
|
||||
* (optional) The namespace from which to
|
||||
* load this entity, or NULL to use the
|
||||
* $service object's default namespace.
|
||||
* Does not apply if this entity is
|
||||
* already loaded (i.e. if $entry is not
|
||||
* NULL).
|
||||
*/
|
||||
public function __construct($service, $path, $entry=NULL, $namespace=NULL)
|
||||
{
|
||||
parent::__construct($service, $path);
|
||||
|
||||
$this->entry = $entry;
|
||||
if ($this->entry != NULL)
|
||||
{
|
||||
if ($namespace !== NULL)
|
||||
throw new InvalidArgumentException(
|
||||
'Cannot specify an entry and a namespace simultaneously. ' .
|
||||
'The namespace will be inferred from the entry.');
|
||||
|
||||
$this->parseContentsFromEntry();
|
||||
$this->namespace = $this->getNamespace(); // extract from 'eai:acl'
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
}
|
||||
|
||||
// === Load ===
|
||||
|
||||
/**
|
||||
* Loads this resource if not already done. Returns self.
|
||||
*
|
||||
* @return Splunk_Entity This entity.
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
protected function validate($fetchArgs=array())
|
||||
{
|
||||
if (!$this->loaded)
|
||||
{
|
||||
$this->load($fetchArgs);
|
||||
assert($this->loaded);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads this resource.
|
||||
*
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
private function load($fetchArgs)
|
||||
{
|
||||
$response = $this->fetch($fetchArgs);
|
||||
$xml = new SimpleXMLElement($response->body);
|
||||
|
||||
$this->entry = $this->extractEntryFromRootXmlElement($xml);
|
||||
$this->parseContentsFromEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches this entity's Atom feed from the Splunk server.
|
||||
*
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
protected function fetch($fetchArgs)
|
||||
{
|
||||
return $this->sendGet('');
|
||||
}
|
||||
|
||||
/** Returns the <entry> element inside the root element. */
|
||||
protected function extractEntryFromRootXmlElement($xml)
|
||||
{
|
||||
if (!Splunk_XmlUtil::isSingleElement($xml->entry))
|
||||
{
|
||||
// Extract name from path since we can't extract it from the
|
||||
// entity content here.
|
||||
$pathComponents = explode('/', $this->path);
|
||||
$name = $pathComponents[count($pathComponents) - 1];
|
||||
|
||||
throw new Splunk_AmbiguousEntityNameException($name);
|
||||
}
|
||||
|
||||
return $xml->entry;
|
||||
}
|
||||
|
||||
/** Parses the entry's contents. */
|
||||
private function parseContentsFromEntry()
|
||||
{
|
||||
$this->content = Splunk_AtomFeed::parseValueInside($this->entry->content);
|
||||
$this->loaded = TRUE;
|
||||
}
|
||||
|
||||
/** Returns a value that indicates whether the entity has been loaded. */
|
||||
protected function isLoaded()
|
||||
{
|
||||
return $this->loaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes this entity's properties from the Splunk server.
|
||||
*
|
||||
* @return Splunk_Entity This entity.
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function refresh()
|
||||
{
|
||||
if ($this->loaded)
|
||||
{
|
||||
// Remember this entity's exact namespace, so that a reload
|
||||
// will occur in the correct namespace.
|
||||
$this->namespace = $this->getNamespace();
|
||||
}
|
||||
|
||||
$this->loaded = FALSE;
|
||||
return $this->validate();
|
||||
}
|
||||
|
||||
// === Accessors ===
|
||||
|
||||
/**
|
||||
* Gets an array that contains the properties of this entity.
|
||||
*
|
||||
* @return array The properties of this entity.
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
return $this->validate()->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this entity.
|
||||
*
|
||||
* @return string The name of this entity.
|
||||
* This name can be used to lookup this entity
|
||||
* from its collection.
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->getTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title of this entity in the REST API.
|
||||
*
|
||||
* @return string The title of this entity in the REST API.
|
||||
*/
|
||||
protected function getTitle()
|
||||
{
|
||||
return (string) $this->validate()->entry->title;
|
||||
}
|
||||
|
||||
/** Gets the namespace in which this entity resides. */
|
||||
protected function getSearchNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the non-wildcarded namespace in which this entity resides.
|
||||
*
|
||||
* @return Splunk_Namespace The non-wildcarded namespace in which this
|
||||
* entity resides.
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
// If this is an entity reference with an exact namespace, return it.
|
||||
if (!$this->loaded)
|
||||
{
|
||||
$effectiveNamespace = $this->namespace;
|
||||
if ($effectiveNamespace === NULL)
|
||||
$effectiveNamespace = $this->service->getNamespace();
|
||||
if ($effectiveNamespace->isExact())
|
||||
return $effectiveNamespace;
|
||||
}
|
||||
|
||||
// Extract the namespace from this entity's content.
|
||||
$acl = $this['eai:acl'];
|
||||
return Splunk_Namespace::createExact(
|
||||
$acl['owner'], $acl['app'], $acl['sharing']);
|
||||
}
|
||||
|
||||
// === ArrayAccess Methods ===
|
||||
|
||||
/**
|
||||
* Gets the value of the specified entity property.
|
||||
*
|
||||
* @param string $key The name of an entity property.
|
||||
* @return string The value of the specified entity property.
|
||||
*/
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return $this->validate()->content[$key];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw new Splunk_UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw new Splunk_UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value that indicates whether the specified entity property exists.
|
||||
*
|
||||
* @param string $key The name of an entity property.
|
||||
* @return string Whether the specified entity property exists.
|
||||
*/
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return isset($this->validate()->content[$key]);
|
||||
}
|
||||
|
||||
// === Operations ===
|
||||
|
||||
/**
|
||||
* Deletes this entity.
|
||||
*
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$this->sendDelete('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this entity's properties.
|
||||
*
|
||||
* Note that the "name" property cannot be updated.
|
||||
*
|
||||
* @param array $args Dictionary of properties that will be changed,
|
||||
* along with their new values.
|
||||
* @return Splunk_Entity This entity.
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function update($args)
|
||||
{
|
||||
if (array_key_exists('name', $args))
|
||||
throw new InvalidArgumentException(
|
||||
'Cannot update the name of an entity.');
|
||||
if (array_key_exists('namespace', $args))
|
||||
throw new InvalidArgumentException(
|
||||
'Cannot override the entity\'s namespace.');
|
||||
|
||||
// Update entity on server
|
||||
$this->sendPost('', $args);
|
||||
|
||||
// Update cached content of entity
|
||||
if ($this->loaded)
|
||||
$this->content = array_merge($this->content, $args);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* HTTP abstraction layer.
|
||||
*
|
||||
* @package Splunk
|
||||
* @internal
|
||||
*/
|
||||
class Splunk_Http
|
||||
{
|
||||
/**
|
||||
* @param array $params (optional) query parameters.
|
||||
* @see request()
|
||||
*/
|
||||
public function get($url, $params=array(), $requestHeaders=array())
|
||||
{
|
||||
return $this->requestWithParams('get', $url, $params, $requestHeaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params (optional) form parameters to send in the request body.
|
||||
* @see request()
|
||||
*/
|
||||
public function post($url, $params=array(), $requestHeaders=array())
|
||||
{
|
||||
$requestHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
|
||||
return $this->request(
|
||||
'post', $url, $requestHeaders, http_build_query($params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params (optional) query parameters.
|
||||
* @see request()
|
||||
*/
|
||||
public function delete($url, $params=array(), $requestHeaders=array())
|
||||
{
|
||||
return $this->requestWithParams('delete', $url, $params, $requestHeaders);
|
||||
}
|
||||
|
||||
private function requestWithParams(
|
||||
$method, $url, $params, $requestHeaders)
|
||||
{
|
||||
$fullUrl = ($params === NULL || count($params) == 0)
|
||||
? $url
|
||||
: $url . '?' . http_build_query($params);
|
||||
|
||||
return $this->request($method, $fullUrl, $requestHeaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP request and returns the response.
|
||||
*
|
||||
* @param string $method HTTP request method (ex: 'get').
|
||||
* @param string $url URL to fetch.
|
||||
* @param array $requestHeaders (optional) dictionary of header names and values.
|
||||
* @param string $requestBody (optional) content to send in the request.
|
||||
* @return Splunk_HttpResponse
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function request(
|
||||
$method, $url, $requestHeaders=array(), $requestBody='')
|
||||
{
|
||||
$isHttp = (substr($url, 0, strlen('http:')) === 'http:');
|
||||
$isHttps = (substr($url, 0, strlen('https:')) === 'https:');
|
||||
|
||||
if (!$isHttp && !$isHttps)
|
||||
{
|
||||
throw new InvalidArgumentException(
|
||||
'URL scheme must be either HTTP or HTTPS.');
|
||||
}
|
||||
|
||||
// The HTTP stream wrapper in PHP < 5.3.7 has a bug which
|
||||
// injects junk at the end of HTTP requests, which breaks
|
||||
// SSL connections. Fallback to cURL-based requests.
|
||||
if ($isHttps && (version_compare(PHP_VERSION, '5.3.7') < 0))
|
||||
return $this->requestWithCurl(
|
||||
$method, $url, $requestHeaders, $requestBody);
|
||||
|
||||
$requestHeaderLines = array();
|
||||
foreach ($requestHeaders as $k => $v)
|
||||
$requestHeaderLines[] = "{$k}: {$v}";
|
||||
|
||||
$fopenContext = stream_context_create(array(
|
||||
'http' => array(
|
||||
'method' => strtoupper($method),
|
||||
'header' => $requestHeaderLines,
|
||||
'content' => $requestBody,
|
||||
'follow_location' => 0, // don't follow HTTP 3xx automatically
|
||||
'max_redirects' => 0, // [PHP 5.2] don't follow HTTP 3xx automatically
|
||||
'ignore_errors' => TRUE, // don't throw exceptions on bad status codes
|
||||
),
|
||||
// LMR FIX!!!!!!
|
||||
'ssl' => array(
|
||||
'verify_peer' => false,
|
||||
'allow_self_signed' => true,
|
||||
'verify_peer_name' => false,
|
||||
),
|
||||
));
|
||||
|
||||
// NOTE: PHP does not perform certificate validation for HTTPS URLs.
|
||||
// NOTE: fopen() magically sets the $http_response_header local variable.
|
||||
$bodyStream = @fopen($url, 'rb', /*use_include_path=*/FALSE, $fopenContext);
|
||||
if ($bodyStream === FALSE)
|
||||
{
|
||||
$errorInfo = error_get_last();
|
||||
$errmsg = $errorInfo['message'];
|
||||
$errno = $errorInfo['type'];
|
||||
throw new Splunk_ConnectException($errmsg, $errno);
|
||||
}
|
||||
|
||||
$headers = array();
|
||||
$headerLines = $http_response_header;
|
||||
$statusLine = array_shift($headerLines);
|
||||
foreach ($headerLines as $line)
|
||||
{
|
||||
list($key, $value) = explode(':', $line, 2);
|
||||
$headers[$key] = trim($value);
|
||||
}
|
||||
|
||||
$statusLineComponents = explode(' ', $statusLine, 3);
|
||||
$httpVersion = $statusLineComponents[0];
|
||||
$status = intval($statusLineComponents[1]);
|
||||
$reason = (count($statusLineComponents) == 3)
|
||||
? $statusLineComponents[2]
|
||||
: '';
|
||||
|
||||
$response = new Splunk_HttpResponse(array(
|
||||
'status' => $status,
|
||||
'reason' => $reason,
|
||||
'headers' => $headers,
|
||||
'bodyStream' => $bodyStream,
|
||||
));
|
||||
|
||||
if ($status >= 400)
|
||||
throw new Splunk_HttpException($response);
|
||||
else
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function requestWithCurl(
|
||||
$method, $url, $requestHeaders=array(), $requestBody='')
|
||||
{
|
||||
$opts = array(
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_TIMEOUT => 60, // secs
|
||||
CURLOPT_RETURNTRANSFER => TRUE,
|
||||
CURLOPT_HEADER => TRUE,
|
||||
// disable SSL certificate validation
|
||||
CURLOPT_SSL_VERIFYPEER => FALSE,
|
||||
// LMR FIX !!!!!!!
|
||||
CURLOPT_SSL_VERIFYHOST => FALSE,
|
||||
);
|
||||
|
||||
foreach ($requestHeaders as $k => $v)
|
||||
$opts[CURLOPT_HTTPHEADER][] = "$k: $v";
|
||||
|
||||
switch ($method)
|
||||
{
|
||||
case 'get':
|
||||
$opts[CURLOPT_HTTPGET] = TRUE;
|
||||
break;
|
||||
case 'post':
|
||||
$opts[CURLOPT_POST] = TRUE;
|
||||
$opts[CURLOPT_POSTFIELDS] = $requestBody;
|
||||
break;
|
||||
default:
|
||||
$opts[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!($curl = curl_init()))
|
||||
throw new Splunk_ConnectException('Unable to initialize cURL.');
|
||||
if (!(curl_setopt_array($curl, $opts)))
|
||||
throw new Splunk_ConnectException(curl_error($curl));
|
||||
// NOTE: The entire HTTP response is read into memory here,
|
||||
// which could be very large. Unfortunately the cURL
|
||||
// interface does not provide a streaming alternative.
|
||||
// To avoid this problem, use PHP 5.3.7+, which doesn't
|
||||
// need cURL to perform HTTP requests.
|
||||
if (!($response = curl_exec($curl)))
|
||||
throw new Splunk_ConnectException(curl_error($curl));
|
||||
|
||||
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
|
||||
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
|
||||
$headerText = substr($response, 0, $headerSize);
|
||||
$body = (strlen($response) == $headerSize)
|
||||
? ''
|
||||
: substr($response, $headerSize);
|
||||
|
||||
$headers = array();
|
||||
$headerLines = explode("\r\n", trim($headerText));
|
||||
$statusLine = array_shift($headerLines);
|
||||
foreach ($headerLines as $line)
|
||||
{
|
||||
list($key, $value) = explode(':', $line, 2);
|
||||
$headers[$key] = trim($value);
|
||||
}
|
||||
|
||||
$statusLineComponents = explode(' ', $statusLine, 3);
|
||||
$httpVersion = $statusLineComponents[0];
|
||||
$reason = count($statusLineComponents) == 3 ? $statusLineComponents[2] : '';
|
||||
|
||||
$response = new Splunk_HttpResponse(array(
|
||||
'status' => $status,
|
||||
'reason' => $reason,
|
||||
'headers' => $headers,
|
||||
'body' => $body,
|
||||
));
|
||||
|
||||
if ($status >= 400)
|
||||
throw new Splunk_HttpException($response);
|
||||
else
|
||||
return $response;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown when an HTTP request fails due to a non 2xx status code.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_HttpException extends Splunk_IOException
|
||||
{
|
||||
private $response;
|
||||
|
||||
// === Init ===
|
||||
|
||||
/** @internal */
|
||||
public function __construct($response)
|
||||
{
|
||||
$detail = Splunk_HttpException::parseFirstMessageFrom($response);
|
||||
|
||||
$message = "HTTP {$response->status} {$response->reason}";
|
||||
if ($detail != NULL)
|
||||
$message .= ' -- ' . $detail;
|
||||
|
||||
$this->response = $response;
|
||||
parent::__construct($message);
|
||||
}
|
||||
|
||||
/** Parses an HTTP response. */
|
||||
private static function parseFirstMessageFrom($response)
|
||||
{
|
||||
if ($response->body == '')
|
||||
return NULL;
|
||||
|
||||
return Splunk_XmlUtil::getTextContentAtXpath(
|
||||
new SimpleXMLElement($response->body),
|
||||
'/response/messages/msg');
|
||||
}
|
||||
|
||||
// === Accessors ===
|
||||
|
||||
/**
|
||||
* Gets an HTTP response.
|
||||
*
|
||||
* @return Splunk_HttpResponse
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a response received from an HTTP request.
|
||||
*
|
||||
* When reading a potentially large response, the 'bodyStream'
|
||||
* property should be used used in preference to the 'body' property,
|
||||
* since it will only keep the current part of the body loaded in memory.
|
||||
*
|
||||
* @package Splunk
|
||||
* @internal
|
||||
*
|
||||
* @property-read integer $status HTTP status code (ex: 200).
|
||||
* @property-read string $reason HTTP reason string (ex: 'OK').
|
||||
* @property-read array $headers Dictionary of headers.
|
||||
* (ex: array('Content-Length' => '0')).
|
||||
* @property-read string $body Content of the response,
|
||||
* as a single byte string.
|
||||
* @property-read resource $bodyStream
|
||||
* Content of the response, as a stream
|
||||
* (of the type returned by fopen()).
|
||||
*/
|
||||
class Splunk_HttpResponse
|
||||
{
|
||||
private $state;
|
||||
private $body; // lazy
|
||||
private $bodyStream; // lazy
|
||||
|
||||
/* @internal */
|
||||
public function __construct($state)
|
||||
{
|
||||
$this->state = $state;
|
||||
$this->body = NULL;
|
||||
$this->bodyStream = NULL;
|
||||
}
|
||||
|
||||
// === Accessors ===
|
||||
|
||||
/** @internal */
|
||||
public function __get($key)
|
||||
{
|
||||
if ($key === 'body')
|
||||
return $this->getBody();
|
||||
else if ($key === 'bodyStream')
|
||||
return $this->getBodyStream();
|
||||
else
|
||||
return $this->state[$key];
|
||||
}
|
||||
|
||||
private function getBody()
|
||||
{
|
||||
if (array_key_exists('body', $this->state))
|
||||
return $this->state['body'];
|
||||
|
||||
if ($this->body === NULL)
|
||||
{
|
||||
if (!array_key_exists('bodyStream', $this->state))
|
||||
throw new Splunk_UnsupportedOperationException(
|
||||
'Response object does not contain body stream.');
|
||||
|
||||
$this->body = Splunk_Util::stream_get_contents(
|
||||
$this->state['bodyStream']);
|
||||
}
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
private function getBodyStream()
|
||||
{
|
||||
if (array_key_exists('bodyStream', $this->state))
|
||||
return $this->state['bodyStream'];
|
||||
|
||||
if ($this->bodyStream === NULL)
|
||||
{
|
||||
if (!array_key_exists('body', $this->state))
|
||||
throw new Splunk_UnsupportedOperationException(
|
||||
'Response object does not contain body.');
|
||||
|
||||
$this->bodyStream = Splunk_StringStream::create($this->state['body']);
|
||||
}
|
||||
return $this->bodyStream;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown when an I/O error occurs.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_IOException extends Exception {}
|
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An index contains events that have been logged to Splunk.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Index extends Splunk_Entity
|
||||
{
|
||||
/**
|
||||
* Logs one or more events to this index.
|
||||
*
|
||||
* It is highly recommended to specify a sourcetype explicitly.
|
||||
*
|
||||
* It is slightly faster to use {@link Splunk_Receiver::submit()}
|
||||
* to accomplish the same task. One fewer network request is needed.
|
||||
*
|
||||
* @param string $data Raw event text.
|
||||
* This may contain data for multiple events.
|
||||
* Under the default configuration, line breaks
|
||||
* ("\n") can be inserted to separate multiple events.
|
||||
* @param array $args (optional) {<br/>
|
||||
* **host**: (optional) The value to populate in the host field
|
||||
* for events from this data input.<br/>
|
||||
* **host_regex**: (optional) A regular expression used to
|
||||
* extract the host value from each event.<br/>
|
||||
* **source**: (optional) The source value to fill in the
|
||||
* metadata for this input's events.<br/>
|
||||
* **sourcetype**: (optional) The sourcetype to apply to
|
||||
* events from this input.<br/>
|
||||
* }
|
||||
* @throws Splunk_IOException
|
||||
* @link http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTinput#receivers.2Fsimple
|
||||
*/
|
||||
public function submit($data, $args=array())
|
||||
{
|
||||
$this->service->getReceiver()->submit($data, array_merge($args, array(
|
||||
'index' => $this->getName(),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a stream for logging events to the specified index.
|
||||
*
|
||||
* It is highly recommended to specify a sourcetype explicitly.
|
||||
*
|
||||
* It is slightly faster to use {@link Splunk_Receiver::attach()}
|
||||
* to accomplish the same task. One fewer network request is needed.
|
||||
*
|
||||
* The returned stream should eventually be closed via fclose().
|
||||
*
|
||||
* @param array $args (optional) {<br/>
|
||||
* **host**: (optional) The value to populate in the host field
|
||||
* for events from this data input.<br/>
|
||||
* **host_regex**: (optional) A regular expression used to
|
||||
* extract the host value from each event.<br/>
|
||||
* **source**: (optional) The source value to fill in the
|
||||
* metadata for this input's events.<br/>
|
||||
* **sourcetype**: (optional) The sourcetype to apply to
|
||||
* events from this input.<br/>
|
||||
* }
|
||||
* @return resource A stream that you can write event text to.
|
||||
* @throws Splunk_IOException
|
||||
* @link http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTinput#receivers.2Fstream
|
||||
*/
|
||||
public function attach($args=array())
|
||||
{
|
||||
return $this->service->getReceiver()->attach(array_merge($args, array(
|
||||
'index' => $this->getName(),
|
||||
)));
|
||||
}
|
||||
}
|
@ -0,0 +1,413 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a running or completed search job.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Job extends Splunk_Entity
|
||||
{
|
||||
// NOTE: These constants are somewhat arbitrary and could use some tuning
|
||||
const DEFAULT_FETCH_MAX_TRIES = 10;
|
||||
const DEFAULT_FETCH_DELAY_PER_RETRY = 0.1; // secs
|
||||
|
||||
// === Load ===
|
||||
|
||||
/*
|
||||
* Job requests sometimes yield an HTTP 204 code when they are in the
|
||||
* process of being created. To hide this from the caller, transparently
|
||||
* retry requests when an HTTP 204 is received.
|
||||
*/
|
||||
protected function fetch($fetchArgs)
|
||||
{
|
||||
$fetchArgs = array_merge(array(
|
||||
'maxTries' => Splunk_Job::DEFAULT_FETCH_MAX_TRIES,
|
||||
'delayPerRetry' => Splunk_Job::DEFAULT_FETCH_DELAY_PER_RETRY,
|
||||
), $fetchArgs);
|
||||
|
||||
for ($numTries = 0; $numTries < $fetchArgs['maxTries']; $numTries++)
|
||||
{
|
||||
$response = parent::fetch($fetchArgs);
|
||||
if ($this->isFullResponse($response))
|
||||
return $response;
|
||||
usleep($fetchArgs['delayPerRetry'] * 1000000);
|
||||
}
|
||||
|
||||
// Give up
|
||||
throw new Splunk_HttpException($response);
|
||||
}
|
||||
|
||||
protected function extractEntryFromRootXmlElement($xml)
|
||||
{
|
||||
// <entry> element is at the root of a job's Atom feed
|
||||
return $xml;
|
||||
}
|
||||
|
||||
// === Ready ===
|
||||
|
||||
/**
|
||||
* Returns a value that indicates whether this job has been loaded.
|
||||
*
|
||||
* @return bool Whether this job has been loaded.
|
||||
*/
|
||||
public function isReady()
|
||||
{
|
||||
return $this->isLoaded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads this job, retrying the specified number of times as necessary.
|
||||
*
|
||||
* @param int $maxTries The maximum number of times to try loading
|
||||
* this job.
|
||||
* @param float $delayPerRetry The number of seconds to wait between
|
||||
* attempts to retry loading this job.
|
||||
* @return Splunk_Entity This entity.
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function makeReady(
|
||||
$maxTries=Splunk_Job::DEFAULT_FETCH_MAX_TRIES,
|
||||
$delayPerRetry=Splunk_Job::DEFAULT_FETCH_DELAY_PER_RETRY)
|
||||
{
|
||||
return $this->validate(/*fetchArgs=*/array(
|
||||
'maxTries' => $maxTries,
|
||||
'delayPerRetry' => $delayPerRetry,
|
||||
));
|
||||
}
|
||||
|
||||
// === Accessors ===
|
||||
|
||||
// Overrides superclass to return the correct ID of this job,
|
||||
// which can be used to lookup this job from the Jobs collection.
|
||||
/**
|
||||
* @see Splunk_Entity::getName()
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this['sid'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the search string executed by this job.
|
||||
*
|
||||
* @return string The search string executed by this job.
|
||||
*/
|
||||
public function getSearch()
|
||||
{
|
||||
return $this->getTitle();
|
||||
}
|
||||
|
||||
// === Results ===
|
||||
|
||||
/**
|
||||
* Returns a value that indicates the percentage of this job's results
|
||||
* that were computed at the time this job was last loaded or
|
||||
* refreshed.
|
||||
*
|
||||
* @return float Percentage of this job's results that were
|
||||
* computed (0.0-1.0) at the time this job was
|
||||
* last loaded or refreshed.
|
||||
* @see Splunk_Entity::refresh()
|
||||
*/
|
||||
public function getProgress()
|
||||
{
|
||||
return floatval($this['doneProgress']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value that indicates whether this job's results were available
|
||||
* at the time this job was last loaded or refreshed.
|
||||
*
|
||||
* @return boolean Whether this job's results were available
|
||||
* at the time this job was last loaded or
|
||||
* refreshed.
|
||||
* @see Splunk_Entity::refresh()
|
||||
*/
|
||||
public function isDone()
|
||||
{
|
||||
return ($this['isDone'] === '1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the results from this job.
|
||||
*
|
||||
* Large result sets will be paginated automatically.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* $job = ...;
|
||||
* while (!$job->refresh()->isDone()) { usleep(0.5 * 1000000); }
|
||||
*
|
||||
* foreach ($job->getResults() as $result)
|
||||
* {
|
||||
* // (See documentation for Splunk_ResultsReader to see how to
|
||||
* // interpret $result.)
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* This method cannot be used to access results from realtime jobs,
|
||||
* which are never done. Use {@link getResultsPreviewPage()} instead.
|
||||
*
|
||||
* @param array $args (optional) {<br/>
|
||||
* **count**: (optional) The maximum number of results to return,
|
||||
* or -1 to return as many as possible.
|
||||
* Defaults to returning as many as possible.<br/>
|
||||
* **offset**: (optional) The offset of the first result to return.
|
||||
* Defaults to 0.<br/>
|
||||
* **pagesize**: (optional) The number of results to fetch from the
|
||||
* server on each request when paginating internally,
|
||||
* or -1 to return as many results as possible.
|
||||
* Defaults to returning as many results as possible.<br/>
|
||||
*
|
||||
* **field_list**: (optional) Comma-separated list of fields to return
|
||||
* in the result set. Defaults to all fields.<br/>
|
||||
* **output_mode**: (optional) The output format of the result. Valid
|
||||
* values:<br/>
|
||||
* - "csv"<br/>
|
||||
* - "raw"<br/>
|
||||
* - "xml": The format parsed by Splunk_ResultsReader.
|
||||
* <br/>
|
||||
* - "json"<br/>
|
||||
* Defaults to "xml".<br/>
|
||||
* You should not change this unless you are parsing
|
||||
* results yourself.<br/>
|
||||
* **search**: (optional) The post processing search to apply to
|
||||
* results. Can be any valid search language string.
|
||||
* For example "search sourcetype=splunkd" will match any
|
||||
* result whose "sourcetype" field is "splunkd".<br/>
|
||||
* }
|
||||
* @return Iterator The results (i.e. transformed events)
|
||||
* of this job, via an iterator.
|
||||
* @throws Splunk_JobNotDoneException
|
||||
* If the results are not ready yet.
|
||||
* Check isDone() to ensure the results are
|
||||
* ready prior to calling this method.
|
||||
* @throws Splunk_IOException
|
||||
* @link http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs.2F.7Bsearch_id.7D.2Fresults
|
||||
*/
|
||||
public function getResults($args=array())
|
||||
{
|
||||
return new Splunk_PaginatedResultsReader($this, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single page of results from this job.
|
||||
*
|
||||
* Most potential callers should use {@link getResults()} instead.
|
||||
* Only use this method if you wish to parse job results yourself
|
||||
* or want to control pagination manually.
|
||||
*
|
||||
* By default, all results are returned. For large
|
||||
* result sets, it is advisable to fetch items using multiple calls with
|
||||
* the paging options (i.e. 'offset' and 'count').
|
||||
*
|
||||
* The format of the results depends on the 'output_mode' argument
|
||||
* (which defaults to "xml"). XML-formatted results can be parsed
|
||||
* using {@link Splunk_ResultsReader}. For example:
|
||||
*
|
||||
* <pre>
|
||||
* $job = ...;
|
||||
* while (!$job->refresh()->isDone()) { usleep(0.5 * 1000000); }
|
||||
*
|
||||
* $results = new Splunk_ResultsReader($job->getResultsPage());
|
||||
* foreach ($results as $result)
|
||||
* {
|
||||
* // (See documentation for Splunk_ResultsReader to see how to
|
||||
* // interpret $result.)
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* This method cannot be used to access results from realtime jobs,
|
||||
* which are never done. Use {@link getResultsPreviewPage()} instead.
|
||||
*
|
||||
* @param array $args (optional) {<br/>
|
||||
* **count**: (optional) The maximum number of results to return,
|
||||
* or -1 to return as many as possible.
|
||||
* Defaults to returning as many as possible.<br/>
|
||||
* **offset**: (optional) The offset of the first result to return.
|
||||
* Defaults to 0.<br/>
|
||||
*
|
||||
* **field_list**: (optional) Comma-separated list of fields to return
|
||||
* in the result set. Defaults to all fields.<br/>
|
||||
* **output_mode**: (optional) The output format of the result. Valid
|
||||
* values:<br/>
|
||||
* - "csv"<br/>
|
||||
* - "raw"<br/>
|
||||
* - "xml": The format parsed by Splunk_ResultsReader.
|
||||
* <br/>
|
||||
* - "json"<br/>
|
||||
* Defaults to "xml".<br/>
|
||||
* You should not change this unless you are parsing
|
||||
* results yourself.<br/>
|
||||
* **search**: (optional) The post processing search to apply to
|
||||
* results. Can be any valid search language string.
|
||||
* For example "search sourcetype=splunkd" will match any
|
||||
* result whose "sourcetype" field is "splunkd".<br/>
|
||||
* }
|
||||
* @return resource The results (i.e. transformed events)
|
||||
* of this job, as a stream.
|
||||
* @throws Splunk_JobNotDoneException
|
||||
* If the results are not ready yet.
|
||||
* Check isDone() to ensure the results are
|
||||
* ready prior to calling this method.
|
||||
* @throws Splunk_IOException
|
||||
* @link http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs.2F.7Bsearch_id.7D.2Fresults
|
||||
*/
|
||||
public function getResultsPage($args=array())
|
||||
{
|
||||
$response = $this->fetchPage('results', $args);
|
||||
if ($response->status == 204)
|
||||
throw new Splunk_JobNotDoneException($response);
|
||||
return $response->bodyStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single page of results from this job,
|
||||
* which may or may not be done running.
|
||||
*
|
||||
* @param array $args (optional) {<br/>
|
||||
* **count**: (optional) The maximum number of results to return,
|
||||
* or -1 to return as many as possible.
|
||||
* Defaults to returning as many as possible.<br/>
|
||||
* **offset**: (optional) The offset of the first result to return.
|
||||
* Defaults to 0.<br/>
|
||||
*
|
||||
* **field_list**: (optional) Comma-separated list of fields to return
|
||||
* in the result set. Defaults to all fields.<br/>
|
||||
* **output_mode**: (optional) The output format of the result. Valid
|
||||
* values:<br/>
|
||||
* - "csv"<br/>
|
||||
* - "raw"<br/>
|
||||
* - "xml": The format parsed by Splunk_ResultsReader.
|
||||
* <br/>
|
||||
* - "json"<br/>
|
||||
* Defaults to "xml".<br/>
|
||||
* You should not change this unless you are parsing
|
||||
* results yourself.<br/>
|
||||
* **search**: (optional) The post processing search to apply to
|
||||
* results. Can be any valid search language string.
|
||||
* For example "search sourcetype=splunkd" will match any
|
||||
* result whose "sourcetype" field is "splunkd".<br/>
|
||||
* }
|
||||
* @return resource The results (i.e. transformed events)
|
||||
* of this job, as a stream.
|
||||
* @throws Splunk_IOException
|
||||
* @link http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs.2F.7Bsearch_id.7D.2Fresults_preview
|
||||
*/
|
||||
public function getResultsPreviewPage($args=array())
|
||||
{
|
||||
$response = $this->fetchPage('results_preview', $args);
|
||||
if ($response->status == 204)
|
||||
{
|
||||
// The REST API throws a 204 when a preview is being generated
|
||||
// and no results are available. This isn't a friendly behavior
|
||||
// for clients.
|
||||
return Splunk_StringStream::create('');
|
||||
}
|
||||
return $response->bodyStream;
|
||||
}
|
||||
|
||||
/** Fetches a page of the specified type. */
|
||||
private function fetchPage($pageType, $args)
|
||||
{
|
||||
$args = array_merge(array(
|
||||
'count' => -1,
|
||||
), $args);
|
||||
|
||||
if ($args['count'] <= 0 && $args['count'] != -1)
|
||||
throw new InvalidArgumentException(
|
||||
'Count must be positive or -1 (infinity).');
|
||||
|
||||
if ($args['count'] == -1)
|
||||
$args['count'] = 0; // infinity value for the REST API
|
||||
|
||||
$response = $this->sendGet("/{$pageType}", $args);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/** Determines whether a response contains full or partial results */
|
||||
private function isFullResponse($response)
|
||||
{
|
||||
if ($response->status == 204)
|
||||
$result = FALSE;
|
||||
else
|
||||
{
|
||||
$responseBody = new SimpleXMLElement($response->body);
|
||||
$dispatchState = implode($responseBody->content->xpath('s:dict/s:key[@name="dispatchState"]/text()'));
|
||||
$result = !($dispatchState === 'QUEUED' || $dispatchState === 'PARSING');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// === Control ===
|
||||
|
||||
/**
|
||||
* Pauses this search job.
|
||||
*
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function pause()
|
||||
{
|
||||
$this->sendControlAction('pause');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpauses this search job.
|
||||
*
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function unpause()
|
||||
{
|
||||
$this->sendControlAction('unpause');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops this search job but keeps the partial results.
|
||||
*
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function finalize()
|
||||
{
|
||||
$this->sendControlAction('finalize');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops this search job and deletes the results.
|
||||
*
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function cancel()
|
||||
{
|
||||
$this->sendControlAction('cancel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts the specified control action.
|
||||
*
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
private function sendControlAction($actionName)
|
||||
{
|
||||
$response = $this->sendPost('/control', array(
|
||||
'action' => $actionName,
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to access a job's results or events
|
||||
* before the job is done.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_JobNotDoneException extends Splunk_HttpException
|
||||
{
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the collection of all search jobs.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Jobs extends Splunk_Collection
|
||||
{
|
||||
// === Operations ===
|
||||
|
||||
/**
|
||||
* @see Splunk_Collection::get()
|
||||
*/
|
||||
public function get($name, $namespace=NULL)
|
||||
{
|
||||
$this->checkName($name);
|
||||
$this->checkNamespace($namespace);
|
||||
|
||||
// Delegate to Job, which already has the special handling to
|
||||
// fetch an individual Job entity.
|
||||
return $this->getReference($name, $namespace)->makeReady();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new search job.
|
||||
*
|
||||
* @param string $search The search query for the job to perform.
|
||||
* @param array $args (optional) Job-specific creation arguments,
|
||||
* merged with {<br/>
|
||||
* **namespace**: (optional) {Splunk_Namespace} The namespace in which
|
||||
* to create the entity. Defaults to the service's
|
||||
* namespace.<br/>
|
||||
* }<br/>
|
||||
* For details, see the
|
||||
* <a href="http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs">
|
||||
* "POST search/jobs"</a>
|
||||
* endpoint in the REST API Documentation.
|
||||
* @return Splunk_Job
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function create($search, $args=array())
|
||||
{
|
||||
$args = array_merge(array(
|
||||
'search' => $search,
|
||||
), $args);
|
||||
|
||||
if (array_key_exists('exec_mode', $args) && ($args['exec_mode'] === 'oneshot'))
|
||||
throw new InvalidArgumentException(
|
||||
'Cannot create oneshot jobs with this method. Use createOneshot() instead.');
|
||||
|
||||
$namespace = Splunk_Util::getArgument($args, 'namespace', NULL);
|
||||
|
||||
$response = $this->sendPost('', $args);
|
||||
$xml = new SimpleXMLElement($response->body);
|
||||
$sid = Splunk_XmlUtil::getTextContentAtXpath($xml, '/response/sid');
|
||||
return $this->getReference($sid, $namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the specified search query and returns results immediately.
|
||||
*
|
||||
* @param string $search The search query for the job to perform.
|
||||
* @param array $args (optional) Job-specific creation arguments,
|
||||
* merged with {<br/>
|
||||
* **namespace**: (optional) {Splunk_Namespace} The namespace in which
|
||||
* to create the entity. Defaults to the service's
|
||||
* namespace.<br/>
|
||||
* }<br/>
|
||||
* For details, see the
|
||||
* <a href="http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs">
|
||||
* "POST search/jobs"</a>
|
||||
* endpoint in the REST API Documentation.
|
||||
* @return string The search results, which can be parsed with
|
||||
* Splunk_ResultsReader.
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function createOneshot($search, $args=array())
|
||||
{
|
||||
$args = array_merge(array(
|
||||
'search' => $search,
|
||||
'exec_mode' => 'oneshot',
|
||||
), $args);
|
||||
|
||||
if ($args['exec_mode'] !== 'oneshot')
|
||||
throw new InvalidArgumentException(
|
||||
'Cannot override "exec_mode" with value other than "oneshot".');
|
||||
|
||||
$response = $this->sendPost('', $args);
|
||||
return $response->body;
|
||||
}
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
// NOTE: Ideally the static constructors for this class wouldn't have any
|
||||
// prefix (like 'create') or suffix. Unfortunately both 'default' and
|
||||
// 'global' are considered keywords in PHP, preventing their use
|
||||
// as static constructor names.
|
||||
/**
|
||||
* Represents a namespace. Every Splunk object belongs to a namespace.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Namespace
|
||||
{
|
||||
private $owner;
|
||||
private $app;
|
||||
private $sharing;
|
||||
|
||||
// === Init ===
|
||||
|
||||
/** Constructs a new namespace with the specified parameters. */
|
||||
private function __construct($owner, $app, $sharing)
|
||||
{
|
||||
$this->owner = $owner;
|
||||
$this->app = $app;
|
||||
$this->sharing = $sharing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the default namespace.
|
||||
*
|
||||
* Objects in the default namespace correspond to the authenticated user
|
||||
* and their default Splunk application.
|
||||
*
|
||||
* @return Splunk_Namespace
|
||||
*/
|
||||
public static function createDefault()
|
||||
{
|
||||
$numArgs = func_num_args(); // must be own line for PHP < 5.3.0
|
||||
Splunk_Namespace::ensureArgumentCountEquals(0, $numArgs);
|
||||
|
||||
static $defaultNamespace = NULL;
|
||||
if ($defaultNamespace === NULL)
|
||||
$defaultNamespace = new Splunk_Namespace(NULL, NULL, 'default');
|
||||
return $defaultNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the namespace containing objects associated with the specified
|
||||
* user and application.
|
||||
*
|
||||
* @param string|NULL $owner name of a Splunk user (ex: "admin"),
|
||||
* or NULL to specify all users.
|
||||
* @param string|NULL $app name of a Splunk app (ex: "search"),
|
||||
* or NULL to specify all apps.
|
||||
* @return Splunk_Namespace
|
||||
*/
|
||||
public static function createUser($owner, $app)
|
||||
{
|
||||
$numArgs = func_num_args(); // must be own line for PHP < 5.3.0
|
||||
Splunk_Namespace::ensureArgumentCountEquals(2, $numArgs);
|
||||
|
||||
if ($owner === '' || $owner === 'nobody' || $owner === '-')
|
||||
throw new InvalidArgumentException('Invalid owner.');
|
||||
if ($app === '' || $app === 'system' || $app === '-')
|
||||
throw new InvalidArgumentException('Invalid app.');
|
||||
if ($owner === NULL)
|
||||
$owner = '-';
|
||||
if ($app === NULL)
|
||||
$app = '-';
|
||||
return new Splunk_Namespace($owner, $app, 'user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the non-global namespace containing objects associated with the
|
||||
* specified application.
|
||||
*
|
||||
* @param string|NULL $app name of a Splunk app (ex: "search"),
|
||||
* or NULL to specify all apps.
|
||||
* @return Splunk_Namespace
|
||||
*/
|
||||
public static function createApp($app)
|
||||
{
|
||||
$numArgs = func_num_args(); // must be own line for PHP < 5.3.0
|
||||
Splunk_Namespace::ensureArgumentCountEquals(1, $numArgs);
|
||||
|
||||
if ($app === '' || $app === 'system' || $app === '-')
|
||||
throw new InvalidArgumentException('Invalid app.');
|
||||
if ($app === NULL)
|
||||
$app = '-';
|
||||
return new Splunk_Namespace('nobody', $app, 'app');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the global namespace containing objects associated with the
|
||||
* specified application.
|
||||
*
|
||||
* @param string|NULL $app name of a Splunk app (ex: "search"),
|
||||
* or NULL to specify all apps.
|
||||
* @return Splunk_Namespace
|
||||
*/
|
||||
public static function createGlobal($app)
|
||||
{
|
||||
$numArgs = func_num_args(); // must be own line for PHP < 5.3.0
|
||||
Splunk_Namespace::ensureArgumentCountEquals(1, $numArgs);
|
||||
|
||||
if ($app === '' || $app === 'system' || $app === '-')
|
||||
throw new InvalidArgumentException('Invalid app.');
|
||||
if ($app === NULL)
|
||||
$app = '-';
|
||||
return new Splunk_Namespace('nobody', $app, 'global');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the system namespace.
|
||||
*
|
||||
* Objects in the system namespace ship with Splunk.
|
||||
*
|
||||
* @return Splunk_Namespace
|
||||
*/
|
||||
public static function createSystem()
|
||||
{
|
||||
$numArgs = func_num_args(); // must be own line for PHP < 5.3.0
|
||||
Splunk_Namespace::ensureArgumentCountEquals(0, $numArgs);
|
||||
|
||||
static $system = NULL;
|
||||
if ($system === NULL)
|
||||
$system = new Splunk_Namespace('nobody', 'system', 'system');
|
||||
return $system;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a non-wildcarded namespace with the specified properties.
|
||||
*
|
||||
* @param string $owner name of a Splunk user (ex: "admin").
|
||||
* @param string $app name of a Splunk app (ex: "search").
|
||||
* @param string $sharing one of {'user', 'app', 'global', 'system'}.
|
||||
* @see user()
|
||||
*/
|
||||
public static function createExact($owner, $app, $sharing)
|
||||
{
|
||||
$numArgs = func_num_args(); // must be own line for PHP < 5.3.0
|
||||
Splunk_Namespace::ensureArgumentCountEquals(3, $numArgs);
|
||||
|
||||
if (!in_array($sharing, array('user', 'app', 'global', 'system')))
|
||||
throw new InvalidArgumentException('Invalid sharing.');
|
||||
if ($owner === NULL || $owner === '' || $owner === '-')
|
||||
throw new InvalidArgumentException('Invalid owner.');
|
||||
if ($app === NULL || $app === '' || $app === '-')
|
||||
throw new InvalidArgumentException('Invalid app.');
|
||||
|
||||
return new Splunk_Namespace($owner, $app, $sharing);
|
||||
}
|
||||
|
||||
// === Accessors ===
|
||||
|
||||
/** Returns the path prefix to use when referencing objects in this
|
||||
namespace. */
|
||||
public function getPathPrefix()
|
||||
{
|
||||
switch ($this->sharing)
|
||||
{
|
||||
case 'default':
|
||||
return '/services/';
|
||||
case 'user':
|
||||
case 'app':
|
||||
case 'global':
|
||||
case 'system':
|
||||
return '/servicesNS/' . urlencode($this->owner) . '/' . urlencode($this->app) . '/';
|
||||
default:
|
||||
throw new Exception("Invalid sharing mode '{$this->sharing}'.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is an exact (non-wildcarded) namespace.
|
||||
*
|
||||
* Within an exact namespace, no two objects can have the same name.
|
||||
*/
|
||||
public function isExact()
|
||||
{
|
||||
return ($this->owner !== '-') && ($this->app !== '-');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user who owns objects in this namespace.
|
||||
*
|
||||
* This operation is only defined for exact namespaces.
|
||||
*/
|
||||
public function getOwner()
|
||||
{
|
||||
$this->ensureExact();
|
||||
return $this->owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the app associated with objects in this namespace.
|
||||
*
|
||||
* This operation is only defined for exact namespaces.
|
||||
*/
|
||||
public function getApp()
|
||||
{
|
||||
$this->ensureExact();
|
||||
return $this->app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sharing mode of this namespace.
|
||||
*
|
||||
* This operation is only defined for exact namespaces.
|
||||
*/
|
||||
public function getSharing()
|
||||
{
|
||||
$this->ensureExact();
|
||||
return $this->sharing;
|
||||
}
|
||||
|
||||
// === Utility ===
|
||||
|
||||
// (Explicitly check the argument count because many creation function
|
||||
// names do not make the required number of arguments clear and PHP
|
||||
// does not check under certain circumstances.)
|
||||
/** Throws an exception if the number of arguments is not what was
|
||||
expected. */
|
||||
private static function ensureArgumentCountEquals($expected, $actual)
|
||||
{
|
||||
if ($actual !== $expected)
|
||||
throw new InvalidArgumentException(
|
||||
"Expected exactly ${expected} arguments.");
|
||||
}
|
||||
|
||||
/** Throws an exception if this namespace is not an exact (non-wildcarded)
|
||||
namespace. */
|
||||
private function ensureExact()
|
||||
{
|
||||
if (!$this->isExact())
|
||||
throw new Splunk_UnsupportedOperationException(
|
||||
'This operation is supported only for exact namespaces.');
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to access a Splunk entity that does not exist.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_NoSuchEntityException extends RuntimeException
|
||||
{
|
||||
/** @internal */
|
||||
public function __construct($name)
|
||||
{
|
||||
parent::__construct("No entity exists with name '{$name}'.");
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @package Splunk
|
||||
* @internal
|
||||
*/
|
||||
class Splunk_PaginatedResultsReader implements Iterator
|
||||
{
|
||||
private $job;
|
||||
private $args;
|
||||
|
||||
private $curPageResultsIterator;
|
||||
private $curOffset;
|
||||
private $limOffset;
|
||||
private $pageMaxSize;
|
||||
private $fieldOrderWasReturned;
|
||||
|
||||
private $currentElement;
|
||||
private $atStart;
|
||||
|
||||
/**
|
||||
* Do not instantiate this class directly.
|
||||
* Please call Splunk_Job::getResults() instead.
|
||||
*/
|
||||
public function __construct($job, $args)
|
||||
{
|
||||
list($args, $pageMaxSize) =
|
||||
Splunk_Util::extractArgument($args, 'pagesize', -1);
|
||||
list($args, $offset) =
|
||||
Splunk_Util::extractArgument($args, 'offset', 0);
|
||||
list($args, $count) =
|
||||
Splunk_Util::extractArgument($args, 'count', -1);
|
||||
|
||||
if ($pageMaxSize <= 0 && $pageMaxSize != -1)
|
||||
throw new InvalidArgumentException(
|
||||
'Page size must be positive or -1 (infinity).');
|
||||
if ($offset < 0)
|
||||
throw new InvalidArgumentException(
|
||||
'Offset must be >= 0.');
|
||||
if ($count <= 0 && $count != -1)
|
||||
throw new InvalidArgumentException(
|
||||
'Count must be positive or -1 (infinity).');
|
||||
|
||||
// (Use PHP_INT_MAX for infinity internally because it works
|
||||
// well with the min() function.)
|
||||
if ($pageMaxSize == -1)
|
||||
$pageMaxSize = PHP_INT_MAX; // internal infinity value
|
||||
if ($count == -1)
|
||||
$count = PHP_INT_MAX; // internal infinity value
|
||||
|
||||
$this->job = $job;
|
||||
$this->args = $args;
|
||||
|
||||
$this->curPageResults = NULL;
|
||||
$this->curOffset = $offset;
|
||||
$this->limOffset = ($count == PHP_INT_MAX) ? PHP_INT_MAX : ($offset + $count);
|
||||
$this->pageMaxSize = $pageMaxSize;
|
||||
$this->fieldOrderWasReturned = FALSE;
|
||||
|
||||
$this->currentElement = $this->readNextElement();
|
||||
$this->atStart = TRUE;
|
||||
}
|
||||
|
||||
// === Iterator Methods ===
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
if ($this->atStart)
|
||||
return;
|
||||
|
||||
throw new Splunk_UnsupportedOperationException(
|
||||
'Cannot rewind after reading past the first element.');
|
||||
}
|
||||
|
||||
public function valid()
|
||||
{
|
||||
return ($this->currentElement !== NULL);
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
$this->currentElement = $this->readNextElement();
|
||||
$this->atStart = FALSE;
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
return $this->currentElement;
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// === Read Next Element ===
|
||||
|
||||
private function readNextElement()
|
||||
{
|
||||
if ($this->curPageResultsIterator == NULL ||
|
||||
!$this->curPageResultsIterator->valid())
|
||||
{
|
||||
if ($this->curOffset >= $this->limOffset)
|
||||
{
|
||||
return NULL; // at EOF
|
||||
}
|
||||
|
||||
$numRemaining = ($this->limOffset == PHP_INT_MAX)
|
||||
? PHP_INT_MAX
|
||||
: ($this->limOffset - $this->curOffset);
|
||||
|
||||
$curPageMaxSize = min($this->pageMaxSize, $numRemaining);
|
||||
if ($curPageMaxSize == PHP_INT_MAX)
|
||||
$curPageMaxSize = -1; // infinity value for getResultsPage()
|
||||
|
||||
$this->curPageResultsIterator = new Splunk_ResultsReader(
|
||||
$this->job->getResultsPage(
|
||||
array_merge($this->args, array(
|
||||
'offset' => $this->curOffset,
|
||||
'count' => $curPageMaxSize,
|
||||
'output_mode' => 'xml',
|
||||
))));
|
||||
if (!$this->curPageResultsIterator->valid())
|
||||
{
|
||||
$this->limOffset = $this->curOffset; // remember EOF position
|
||||
return NULL; // at EOF
|
||||
}
|
||||
}
|
||||
|
||||
assert($this->curPageResultsIterator->valid());
|
||||
$element = $this->curPageResultsIterator->current();
|
||||
$this->curPageResultsIterator->next();
|
||||
|
||||
if ($element instanceof Splunk_ResultsFieldOrder)
|
||||
{
|
||||
// Only return the field order once.
|
||||
if ($this->fieldOrderWasReturned)
|
||||
{
|
||||
// Don't return the field order again.
|
||||
// Skip to the next element.
|
||||
return $this->readNextElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->fieldOrderWasReturned = TRUE;
|
||||
}
|
||||
}
|
||||
else if (is_array($element))
|
||||
{
|
||||
$this->curOffset++;
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides methods for logging events to a Splunk index.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Receiver
|
||||
{
|
||||
private $service;
|
||||
|
||||
/** @internal */
|
||||
public function __construct($service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
// === Operations ===
|
||||
|
||||
/**
|
||||
* Logs one or more events to the specified index.
|
||||
*
|
||||
* In addition to the index name it is highly recommended to specify
|
||||
* a sourcetype explicitly.
|
||||
*
|
||||
* @param string $data Raw event text.
|
||||
* This may contain data for multiple events.
|
||||
* Under the default configuration, line breaks
|
||||
* ("\n") can be inserted to separate multiple events.
|
||||
* @param array $args (optional) {<br/>
|
||||
* **host**: (optional) The value to populate in the host field
|
||||
* for events from this data input.<br/>
|
||||
* **host_regex**: (optional) A regular expression used to
|
||||
* extract the host value from each event.<br/>
|
||||
* **index**: (optional) The index to send events from this
|
||||
* input to. Highly recommended. Defaults to "default".<br/>
|
||||
* **source**: (optional) The source value to fill in the
|
||||
* metadata for this input's events.<br/>
|
||||
* **sourcetype**: (optional) The sourcetype to apply to
|
||||
* events from this input.<br/>
|
||||
* }
|
||||
* @throws Splunk_IOException
|
||||
* @link http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTinput#receivers.2Fsimple
|
||||
*/
|
||||
public function submit($data, $args=array())
|
||||
{
|
||||
// (Avoid the normal post() method, since we aren't sending form data.)
|
||||
$this->service->sendRequest(
|
||||
'post', '/services/receivers/simple',
|
||||
array('Content-Type' => 'text/plain'),
|
||||
$data,
|
||||
$args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a stream for logging events to the specified index.
|
||||
*
|
||||
* In addition to the index name it is highly recommended to specify
|
||||
* a sourcetype explicitly.
|
||||
*
|
||||
* The returned stream should eventually be closed via fclose().
|
||||
*
|
||||
* @param array $args (optional) {<br/>
|
||||
* **host**: (optional) The value to populate in the host field
|
||||
* for events from this data input.<br/>
|
||||
* **host_regex**: (optional) A regular expression used to
|
||||
* extract the host value from each event.<br/>
|
||||
* **index**: (optional) The index to send events from this
|
||||
* input to. Highly recommended. Defaults to "default".<br/>
|
||||
* **source**: (optional) The source value to fill in the
|
||||
* metadata for this input's events.<br/>
|
||||
* **sourcetype**: (optional) The sourcetype to apply to
|
||||
* events from this input.<br/>
|
||||
* }
|
||||
* @return resource A stream that you can write event text to.
|
||||
* @throws Splunk_IOException
|
||||
* @link http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTinput#receivers.2Fstream
|
||||
*/
|
||||
public function attach($args=array())
|
||||
{
|
||||
$scheme = $this->service->getScheme();
|
||||
$host = $this->service->getHost();
|
||||
$port = $this->service->getPort();
|
||||
|
||||
$errno = 0;
|
||||
$errstr = '';
|
||||
if ($scheme == 'http')
|
||||
$stream = @fsockopen($host, $port, /*out*/ $errno, /*out*/ $errstr);
|
||||
else if ($scheme == 'https')
|
||||
$stream = @fsockopen('ssl://' . $host, $port, /*out*/ $errno, /*out*/ $errstr);
|
||||
else
|
||||
throw new Splunk_UnsupportedOperationException(
|
||||
'Unsupported URL scheme.');
|
||||
if ($stream === FALSE)
|
||||
throw new Splunk_ConnectException($errstr, $errno);
|
||||
|
||||
$path = '/services/receivers/stream?' . http_build_query($args);
|
||||
$token = $this->service->getToken();
|
||||
|
||||
$headers = array(
|
||||
"POST {$path} HTTP/1.1\r\n",
|
||||
"Host: {$host}:{$port}\r\n",
|
||||
"Accept-Encoding: identity\r\n",
|
||||
"Authorization: {$token}\r\n",
|
||||
"X-Splunk-Input-Mode: Streaming\r\n",
|
||||
"\r\n",
|
||||
);
|
||||
Splunk_Util::fwriteall($stream, implode('', $headers));
|
||||
|
||||
return $stream;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a statement of which fields will be returned in a results stream,
|
||||
* and what their relative ordering is.
|
||||
*
|
||||
* @package Splunk
|
||||
* @see Splunk_ResultsReader
|
||||
*/
|
||||
class Splunk_ResultsFieldOrder
|
||||
{
|
||||
private $fieldNames;
|
||||
|
||||
/** @internal */
|
||||
public function __construct($fieldNames)
|
||||
{
|
||||
$this->fieldNames = $fieldNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ordered list of field names that will be returned in the results stream.
|
||||
*
|
||||
* @return array A ordered list of the field names that will be returned
|
||||
* in the results stream.
|
||||
*/
|
||||
public function getFieldNames()
|
||||
{
|
||||
return $this->fieldNames;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a message received in a results stream.
|
||||
*
|
||||
* @package Splunk
|
||||
* @see Splunk_ResultsReader
|
||||
*/
|
||||
class Splunk_ResultsMessage
|
||||
{
|
||||
private $type;
|
||||
private $text;
|
||||
|
||||
/** @internal */
|
||||
public function __construct($type, $text)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of this message.
|
||||
*
|
||||
* @return string The type of this message (ex: 'DEBUG').
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text of this message.
|
||||
*
|
||||
* @return string The text of this message.
|
||||
*/
|
||||
public function getText()
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
}
|
@ -0,0 +1,314 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parses XML search results received from jobs.
|
||||
*
|
||||
* Results are obtained by iterating over an instance of this class
|
||||
* using a foreach loop. Each result can be a Splunk_ResultsFieldOrder,
|
||||
* a Splunk_ResultsMessage, an associative array, or potentially instances
|
||||
* of other classes in the future.
|
||||
*
|
||||
* If the result is an associative array, it maps each
|
||||
* field name to either a single value or an array of values.
|
||||
*
|
||||
* <pre>
|
||||
* $resultsReader = new Splunk_ResultsReader(...);
|
||||
* foreach ($resultsReader as $result)
|
||||
* {
|
||||
* if ($result instanceof Splunk_ResultsFieldOrder)
|
||||
* {
|
||||
* // Process the field order
|
||||
* print "FIELDS: " . implode(',', $result->getFieldNames()) . "\r\n";
|
||||
* }
|
||||
* else if ($result instanceof Splunk_ResultsMessage)
|
||||
* {
|
||||
* // Process a message
|
||||
* print "[{$result->getType()}] {$result->getText()}\r\n";
|
||||
* }
|
||||
* else if (is_array($result))
|
||||
* {
|
||||
* // Process a row
|
||||
* print "{\r\n";
|
||||
* foreach ($result as $key => $valueOrValues)
|
||||
* {
|
||||
* if (is_array($valueOrValues))
|
||||
* {
|
||||
* $values = $valueOrValues;
|
||||
* $valuesString = implode(',', $values);
|
||||
* print " {$key} => [{$valuesString}]\r\n";
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* $value = $valueOrValues;
|
||||
* print " {$key} => {$value}\r\n";
|
||||
* }
|
||||
* }
|
||||
* print "}\r\n";
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // Ignore unknown result type
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_ResultsReader implements Iterator
|
||||
{
|
||||
private $emptyXml;
|
||||
private $xmlReader;
|
||||
|
||||
private $currentElement;
|
||||
private $atStart;
|
||||
|
||||
/**
|
||||
* Constructs a new search results string or stream.
|
||||
*
|
||||
* @param string|resource $streamOrXmlString
|
||||
* A string or stream containing results obtained from the
|
||||
* {@link Splunk_Job::getResultsPage()} method.
|
||||
*/
|
||||
public function __construct($streamOrXmlString)
|
||||
{
|
||||
if (is_string($streamOrXmlString))
|
||||
{
|
||||
$string = $streamOrXmlString;
|
||||
$stream = Splunk_StringStream::create($string);
|
||||
}
|
||||
else
|
||||
{
|
||||
$stream = $streamOrXmlString;
|
||||
}
|
||||
|
||||
// Search jobs lacking results return a blank document (with HTTP 200).
|
||||
if (feof($stream))
|
||||
{
|
||||
$this->emptyXml = TRUE;
|
||||
|
||||
$this->currentElement = NULL;
|
||||
$this->atStart = TRUE;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->emptyXml = FALSE;
|
||||
}
|
||||
|
||||
$streamUri = Splunk_StreamStream::createUriForStream($stream);
|
||||
|
||||
$this->xmlReader = new XMLReader();
|
||||
$this->xmlReader->open($streamUri);
|
||||
|
||||
$this->currentElement = $this->readNextElement();
|
||||
$this->atStart = TRUE;
|
||||
}
|
||||
|
||||
// === Iterator Methods ===
|
||||
|
||||
/** @internal */
|
||||
public function rewind()
|
||||
{
|
||||
if ($this->atStart)
|
||||
return;
|
||||
|
||||
throw new Splunk_UnsupportedOperationException(
|
||||
'Cannot rewind after reading past the first element.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value that indicates whether there are any more elements in the stream.
|
||||
*
|
||||
* @return boolean Whether there are any more elements.
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return ($this->currentElement !== NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances this iterator to the next element.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->currentElement = $this->readNextElement();
|
||||
$this->atStart = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current element of this iterator.
|
||||
*
|
||||
* @return Splunk_ResultsFieldOrder|Splunk_ResultsMessage|array|mixed
|
||||
* The current element of this iterator.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->currentElement;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function key()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// === Read Next Element ===
|
||||
|
||||
/** Returns the next element in the stream. */
|
||||
private function readNextElement()
|
||||
{
|
||||
$xr = $this->xmlReader;
|
||||
|
||||
if ($this->emptyXml)
|
||||
return NULL;
|
||||
|
||||
while ($xr->read())
|
||||
{
|
||||
// Read: /meta
|
||||
if ($xr->nodeType == XMLReader::ELEMENT &&
|
||||
$xr->name === 'meta')
|
||||
{
|
||||
return $this->readMeta();
|
||||
}
|
||||
|
||||
// Read: /messages/msg
|
||||
if ($xr->nodeType == XMLReader::ELEMENT &&
|
||||
$xr->name === 'msg')
|
||||
{
|
||||
$type = $xr->getAttribute('type');
|
||||
|
||||
// Read: /messages/msg/[TEXT]
|
||||
if (!$xr->read())
|
||||
break;
|
||||
assert ($xr->nodeType == XMLReader::TEXT);
|
||||
$text = $xr->value;
|
||||
|
||||
return new Splunk_ResultsMessage($type, $text);
|
||||
}
|
||||
|
||||
// Read: /result
|
||||
if ($xr->nodeType == XMLReader::ELEMENT &&
|
||||
$xr->name === 'result')
|
||||
{
|
||||
return $this->readResult();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Reads metadata from the stream. */
|
||||
private function readMeta()
|
||||
{
|
||||
$xr = $this->xmlReader;
|
||||
|
||||
$insideFieldOrder = FALSE;
|
||||
$fieldsNames = NULL;
|
||||
|
||||
while ($xr->read())
|
||||
{
|
||||
// Begin: /meta/fieldOrder
|
||||
if ($xr->nodeType == XMLReader::ELEMENT &&
|
||||
$xr->name === 'fieldOrder')
|
||||
{
|
||||
$insideFieldOrder = TRUE;
|
||||
$fieldsNames = array();
|
||||
}
|
||||
|
||||
// Read: /meta/fieldOrder/field/[TEXT]
|
||||
if ($insideFieldOrder &&
|
||||
$xr->nodeType == XMLReader::TEXT)
|
||||
{
|
||||
$fieldsNames[] = $xr->value;
|
||||
}
|
||||
|
||||
// End: /meta/fieldOrder
|
||||
if ($xr->nodeType == XMLReader::END_ELEMENT &&
|
||||
$xr->name === 'fieldOrder')
|
||||
{
|
||||
return new Splunk_ResultsFieldOrder($fieldsNames);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception('Syntax error in <meta> element.');
|
||||
}
|
||||
|
||||
/** Returns search results from the stream. */
|
||||
private function readResult()
|
||||
{
|
||||
$xr = $this->xmlReader;
|
||||
|
||||
$lastKey = NULL;
|
||||
$lastValues = array();
|
||||
$insideValue = FALSE;
|
||||
|
||||
$result = array();
|
||||
while ($xr->read())
|
||||
{
|
||||
// Begin: /result/field
|
||||
if ($xr->nodeType == XMLReader::ELEMENT &&
|
||||
$xr->name === 'field')
|
||||
{
|
||||
$lastKey = $xr->getAttribute('k');
|
||||
$lastValues = array();
|
||||
}
|
||||
|
||||
// Begin: /result/field/value
|
||||
// Begin: /result/field/v
|
||||
if ($xr->nodeType == XMLReader::ELEMENT &&
|
||||
($xr->name === 'value' || $xr->name === 'v'))
|
||||
{
|
||||
$insideValue = TRUE;
|
||||
}
|
||||
|
||||
// Read: /result/field/value/text/[TEXT]
|
||||
// Read: /result/field/v/[TEXT]
|
||||
if ($insideValue &&
|
||||
$xr->nodeType == XMLReader::TEXT)
|
||||
{
|
||||
$lastValues[] = $xr->value;
|
||||
}
|
||||
|
||||
// End: /result/field/value
|
||||
// End: /result/field/v
|
||||
if ($xr->nodeType == XMLReader::END_ELEMENT &&
|
||||
($xr->name === 'value' || $xr->name === 'v'))
|
||||
{
|
||||
$insideValue = FALSE;
|
||||
}
|
||||
|
||||
// End: /result/field
|
||||
if ($xr->nodeType == XMLReader::END_ELEMENT &&
|
||||
$xr->name === 'field')
|
||||
{
|
||||
if (count($lastValues) === 1)
|
||||
{
|
||||
$lastValues = $lastValues[0];
|
||||
}
|
||||
$result[$lastKey] = $lastValues;
|
||||
}
|
||||
|
||||
// End: /result
|
||||
if ($xr->nodeType == XMLReader::END_ELEMENT &&
|
||||
$xr->name === 'result')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a saved search.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_SavedSearch extends Splunk_Entity
|
||||
{
|
||||
// === Operations ===
|
||||
|
||||
/**
|
||||
* Runs this saved search and returns the resulting search job.
|
||||
*
|
||||
* @param array $args (optional) Additional arguments.
|
||||
* For details, see the
|
||||
* <a href="http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#saved.2Fsearches.2F.7Bname.7D.2Fdispatch">
|
||||
* "POST saved/searches/{name}/dispatch"</a>
|
||||
* endpoint in the REST API Documentation.
|
||||
* @return Splunk_Job
|
||||
* The created search job.
|
||||
*/
|
||||
public function dispatch($args=array())
|
||||
{
|
||||
$response = $this->sendPost('/dispatch', $args);
|
||||
$xml = new SimpleXMLElement($response->body);
|
||||
$sid = Splunk_XmlUtil::getTextContentAtXpath($xml, '/response/sid');
|
||||
|
||||
return $this->service->getJobs()->getReference(
|
||||
$sid, $this->getNamespace());
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides an object-oriented interface to access entities of a Splunk server.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_Service extends Splunk_Context
|
||||
{
|
||||
/**
|
||||
* Constructs a new service with the specified parameters.
|
||||
*
|
||||
* @see Splunk_Context::__construct()
|
||||
*/
|
||||
public function __construct($args=array())
|
||||
{
|
||||
parent::__construct($args);
|
||||
}
|
||||
|
||||
// === Endpoints ===
|
||||
|
||||
/**
|
||||
* Gets the collection of indexes on this server.
|
||||
*
|
||||
* @return Splunk_Collection The collection of indexes on this server.
|
||||
*/
|
||||
public function getIndexes()
|
||||
{
|
||||
return new Splunk_Collection($this, 'data/indexes/', 'Splunk_Index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the collection of search jobs on this server.
|
||||
*
|
||||
* @return Splunk_Jobs The collection of search jobs on this server.
|
||||
*/
|
||||
public function getJobs()
|
||||
{
|
||||
return new Splunk_Jobs($this, 'search/jobs/', 'Splunk_Job');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an interface to send events to this server.
|
||||
*
|
||||
* @return Splunk_Receiver An interface to send events to this server.
|
||||
*/
|
||||
public function getReceiver()
|
||||
{
|
||||
return new Splunk_Receiver($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the collection of saved searches on this server.
|
||||
*
|
||||
* @return Splunk_Collection The collection of saved searches on this server.
|
||||
*/
|
||||
public function getSavedSearches()
|
||||
{
|
||||
return new Splunk_Collection($this, 'saved/searches/', 'Splunk_SavedSearch');
|
||||
}
|
||||
|
||||
// === Convenience ===
|
||||
|
||||
/**
|
||||
* Creates a new search job.
|
||||
*
|
||||
* @param string $search The search query for the job to perform.
|
||||
* @param array $args (optional) Job-specific creation arguments,
|
||||
* merged with {<br/>
|
||||
* **namespace**: (optional) {Splunk_Namespace} The namespace in which
|
||||
* to create the entity. Defaults to the service's
|
||||
* namespace.<br/>
|
||||
* }<br/>
|
||||
* For details, see the
|
||||
* <a href="http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs">
|
||||
* "POST search/jobs"</a>
|
||||
* endpoint in the REST API Documentation.
|
||||
* @return Splunk_Job
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function search($search, $args=array())
|
||||
{
|
||||
return $this->getJobs()->create($search, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the specified search query and returns results immediately.
|
||||
*
|
||||
* @param string $search The search query for the job to perform.
|
||||
* @param array $args (optional) Job-specific creation arguments,
|
||||
* merged with {<br/>
|
||||
* **namespace**: (optional) {Splunk_Namespace} The namespace in which
|
||||
* to create the entity. Defaults to the service's
|
||||
* namespace.<br/>
|
||||
* }<br/>
|
||||
* For details, see the
|
||||
* <a href="http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs">
|
||||
* "POST search/jobs"</a>
|
||||
* endpoint in the REST API Documentation.
|
||||
* @return string The search results, which can be parsed with
|
||||
* Splunk_ResultsReader.
|
||||
* @throws Splunk_IOException
|
||||
*/
|
||||
public function oneshotSearch($search, $args=array())
|
||||
{
|
||||
return $this->getJobs()->createOneshot($search, $args);
|
||||
}
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A stream wrapper implementation that reads from another underlying stream.
|
||||
*
|
||||
* This is useful to pass a stream as an input to a PHP API that only accepts
|
||||
* URIs for its inputs, such as XMLReader.
|
||||
*
|
||||
* @package Splunk
|
||||
* @internal
|
||||
*/
|
||||
class Splunk_StreamStream
|
||||
{
|
||||
// === Registration ===
|
||||
|
||||
private static $registeredStreams = array();
|
||||
|
||||
/**
|
||||
* Makes the specified stream accessible by URI.
|
||||
*
|
||||
* @param resource $stream A stream created by fopen().
|
||||
* @return string A URI that the provided stream can be
|
||||
* opened with via another fopen() call.
|
||||
* For example "splunkstream://5016d2d5c9d90".
|
||||
*/
|
||||
public static function createUriForStream($stream)
|
||||
{
|
||||
$streamId = uniqid();
|
||||
Splunk_StreamStream::$registeredStreams[$streamId] = $stream;
|
||||
return 'splunkstream://' . $streamId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer The number of streams that have been
|
||||
* registered with createUriForStream()
|
||||
* that haven't been closed.
|
||||
*/
|
||||
public static function getOpenStreamCount()
|
||||
{
|
||||
return count(Splunk_StreamStream::$registeredStreams);
|
||||
}
|
||||
|
||||
// === Stream ===
|
||||
|
||||
private $stream;
|
||||
private $streamId;
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
$url = parse_url($path);
|
||||
$streamId = $url['host'];
|
||||
|
||||
if (array_key_exists($streamId, Splunk_StreamStream::$registeredStreams))
|
||||
{
|
||||
$this->stream = Splunk_StreamStream::$registeredStreams[$streamId];
|
||||
$this->streamId = $streamId;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
public function stream_read($count)
|
||||
{
|
||||
return fread($this->stream, $count);
|
||||
}
|
||||
|
||||
public function stream_write($data)
|
||||
{
|
||||
return fwrite($this->stream, $data);
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
return fseek($this->stream, $offset, $whence);
|
||||
}
|
||||
|
||||
public function stream_tell()
|
||||
{
|
||||
return ftell($this->stream);
|
||||
}
|
||||
|
||||
public function stream_eof()
|
||||
{
|
||||
return feof($this->stream);
|
||||
}
|
||||
|
||||
public function stream_stat()
|
||||
{
|
||||
return fstat($this->stream);
|
||||
}
|
||||
|
||||
public function stream_flush()
|
||||
{
|
||||
return fflush($this->stream);
|
||||
}
|
||||
|
||||
public function stream_close()
|
||||
{
|
||||
fclose($this->stream);
|
||||
|
||||
// (When called from a shutdown hook, sometimes this variable no
|
||||
// longer exists when this method is called.)
|
||||
if (isset(Splunk_StreamStream::$registeredStreams))
|
||||
{
|
||||
unset(Splunk_StreamStream::$registeredStreams[$this->streamId]);
|
||||
}
|
||||
}
|
||||
|
||||
public function url_stat($path, $flags)
|
||||
{
|
||||
$url = parse_url($path);
|
||||
$streamId = $url['host'];
|
||||
|
||||
if (array_key_exists($streamId, Splunk_StreamStream::$registeredStreams))
|
||||
{
|
||||
$stream = Splunk_StreamStream::$registeredStreams[$streamId];
|
||||
$statResult = fstat($stream);
|
||||
if ($statResult === FALSE)
|
||||
{
|
||||
/*
|
||||
* The API for url_stat() always requires a valid (non-FALSE),
|
||||
* result, even though fstat() can return FALSE. The docs say
|
||||
* to set unknown values to "a rational value (usually 0)".
|
||||
*
|
||||
* XMLReader::open() enforces this, printing out a cryptic
|
||||
* "Unable to open source data" error if a FALSE result for
|
||||
* url_stat() is returned.
|
||||
*/
|
||||
return array(
|
||||
'dev' => 0,
|
||||
'ino' => 0,
|
||||
'mode' => 0,
|
||||
'nlink' => 1,
|
||||
'uid' => 0,
|
||||
'gid' => 0,
|
||||
'rdev' => -1,
|
||||
'size' => 0,
|
||||
'atime' => 0,
|
||||
'mtime' => 0,
|
||||
'ctime' => 0,
|
||||
'blksize' => -1,
|
||||
'blocks' => -1,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $statResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stream_wrapper_register('splunkstream', 'Splunk_StreamStream') or
|
||||
die('Could not register protocol.');
|
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a stream that reads from a string.
|
||||
*
|
||||
* @package Splunk
|
||||
* @internal
|
||||
*/
|
||||
class Splunk_StringStream
|
||||
{
|
||||
/** (Prevent construction.) **/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return resource A stream that reads from the specified byte string.
|
||||
*/
|
||||
public static function create($string)
|
||||
{
|
||||
$stream = fopen('php://memory', 'rwb');
|
||||
Splunk_Util::fwriteall($stream, $string);
|
||||
fseek($stream, 0);
|
||||
|
||||
/*
|
||||
* fseek() causes the next call to feof() to always return FALSE,
|
||||
* which is undesirable if we seeked to the EOF. In this case,
|
||||
* attempt a read past EOF so that the next call to feof() returns
|
||||
* TRUE as expected.
|
||||
*/
|
||||
if ($string === '')
|
||||
fread($stream, 1); // trigger EOF explicitly
|
||||
|
||||
return $stream;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown if the requested operation is not supported.
|
||||
*
|
||||
* @package Splunk
|
||||
*/
|
||||
class Splunk_UnsupportedOperationException extends RuntimeException
|
||||
{
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal utility functions for the PHP SDK.
|
||||
*
|
||||
* @package Splunk
|
||||
* @internal
|
||||
*/
|
||||
class Splunk_Util
|
||||
{
|
||||
/**
|
||||
* Extracts the value for the specified $key from the specified $dict.
|
||||
*
|
||||
* @param array $dict
|
||||
* @param mixed $key
|
||||
* @param mixed $defaultValue
|
||||
* @return array {
|
||||
* [0] => $dict without $key
|
||||
* [1] => $dict[$key] if it exists, or $defaultValue if it does not
|
||||
* }
|
||||
*/
|
||||
public static function extractArgument($dict, $key, $defaultValue)
|
||||
{
|
||||
$value = array_key_exists($key, $dict) ? $dict[$key] : $defaultValue;
|
||||
unset($dict[$key]);
|
||||
return array($dict, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for the specified $key from the specified $dict,
|
||||
* returning the $defaultValue in the key is not found.
|
||||
*
|
||||
* @param array $dict
|
||||
* @param mixed $key
|
||||
* @param mixed $defaultValue
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getArgument($dict, $key, $defaultValue)
|
||||
{
|
||||
return array_key_exists($key, $dict) ? $dict[$key] : $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes $data to $stream.
|
||||
*
|
||||
* @throws Splunk_IOException If an I/O error occurs.
|
||||
*/
|
||||
public static function fwriteall($stream, $data)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
$numBytesWritten = fwrite($stream, $data);
|
||||
if ($numBytesWritten === FALSE)
|
||||
{
|
||||
$errorInfo = error_get_last();
|
||||
$errmsg = $errorInfo['message'];
|
||||
$errno = $errorInfo['type'];
|
||||
throw new Splunk_IOException($errmsg, $errno);
|
||||
}
|
||||
if ($numBytesWritten == strlen($data))
|
||||
return;
|
||||
$data = substr($data, $numBytesWritten);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entire contents of the specified stream.
|
||||
* Throws a Splunk_IOException upon error.
|
||||
*
|
||||
* @param resource $stream A stream.
|
||||
* @return string The contents of the specified stream.
|
||||
* @throws Splunk_IOException If an I/O error occurs.
|
||||
*/
|
||||
public static function stream_get_contents($stream)
|
||||
{
|
||||
// HACK: Clear the last error
|
||||
@trigger_error('');
|
||||
|
||||
$oldError = error_get_last();
|
||||
$body = @stream_get_contents($stream);
|
||||
$newError = error_get_last();
|
||||
|
||||
// HACK: Detecting whether stream_get_contents() has failed is not
|
||||
// strightforward because it can either return FALSE or ''.
|
||||
// However '' is also a legal return value in non-error scenarios.
|
||||
if ($newError != $oldError)
|
||||
{
|
||||
$errorInfo = error_get_last();
|
||||
$errmsg = $errorInfo['message'];
|
||||
$errno = $errorInfo['type'];
|
||||
throw new Splunk_IOException($errmsg, $errno);
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2013 Splunk, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utilities for manipulating SimpleXMLElement objects.
|
||||
*
|
||||
* @package Splunk
|
||||
* @internal
|
||||
*/
|
||||
class Splunk_XmlUtil
|
||||
{
|
||||
/**
|
||||
* Returns whether the specified XML element exists.
|
||||
*
|
||||
* @param SimpleXMLElement $xml
|
||||
* @return boolean
|
||||
*/
|
||||
public static function elementExists($xml)
|
||||
{
|
||||
return $xml->getName() != '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SimpleXMLElement $xml
|
||||
* @param string $attributeName
|
||||
* @return string|NULL
|
||||
*/
|
||||
public static function getAttributeValue($xml, $attributeName)
|
||||
{
|
||||
return (isset($xml->attributes()->$attributeName))
|
||||
? (string) $xml->attributes()->$attributeName
|
||||
: NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SimpleXMLElement $xml
|
||||
* @return string
|
||||
*/
|
||||
public static function getTextContent($xml)
|
||||
{
|
||||
// HACK: Some versions of PHP 5 can't access the [0] element
|
||||
// of a SimpleXMLElement object properly.
|
||||
return (string) $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SimpleXMLElement $xml
|
||||
* @param string $xpathExpr
|
||||
* @return string|NULL
|
||||
*/
|
||||
public static function getTextContentAtXpath($xml, $xpathExpr)
|
||||
{
|
||||
$matchingElements = $xml->xpath($xpathExpr);
|
||||
return (count($matchingElements) == 0)
|
||||
? NULL
|
||||
: Splunk_XmlUtil::getTextContent($matchingElements[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified SimpleXMLElement represents a unique
|
||||
* element or false if it represents a collection of elements.
|
||||
*
|
||||
* @param SimpleXMLElement $xml
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSingleElement($xml)
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($xml as $item)
|
||||
{
|
||||
$count++;
|
||||
if ($count >= 2)
|
||||
return false;
|
||||
}
|
||||
return ($count == 1);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue