Skip to content

Commit c09bc15

Browse files
committed
Merge pull request #566 from jlinn/snapshot
Add snapshot / restore functionality
2 parents 1c7c432 + 4091767 commit c09bc15

File tree

3 files changed

+269
-0
lines changed

3 files changed

+269
-0
lines changed

changes.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
CHANGES
2+
2014-03-07
3+
- Add snapshot / restore functionality (Elastica\Snapshot) #566
24

35
2014-03-04
46
- Add PHP 5.6 to travis test environment

lib/Elastica/Snapshot.php

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
3+
namespace Elastica;
4+
5+
use Elastica\Exception\NotFoundException;
6+
use Elastica\Exception\ResponseException;
7+
8+
/**
9+
* Class Snapshot
10+
* @package Elastica
11+
* @link http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/modules-snapshots.html
12+
*/
13+
class Snapshot
14+
{
15+
/**
16+
* @var Client
17+
*/
18+
protected $_client;
19+
20+
/**
21+
* @param Client $client
22+
*/
23+
public function __construct(Client $client)
24+
{
25+
$this->_client = $client;
26+
}
27+
28+
/**
29+
* Register a snapshot repository
30+
* @param string $name the name of the repository
31+
* @param string $type the repository type ("fs" for file system)
32+
* @param array $settings Additional repository settings. If type "fs" is used, the "location" setting must be provided.
33+
* @return Response
34+
*/
35+
public function registerRepository($name, $type, $settings = array())
36+
{
37+
$data = array(
38+
'type' => $type,
39+
'settings' => $settings
40+
);
41+
return $this->request($name, Request::PUT, $data);
42+
}
43+
44+
/**
45+
* Retrieve a repository record by name
46+
* @param string $name the name of the desired repository
47+
* @throws Exception\ResponseException
48+
* @throws Exception\NotFoundException
49+
* @return array
50+
*/
51+
public function getRepository($name)
52+
{
53+
try {
54+
$response = $this->request($name);
55+
} catch (ResponseException $e) {
56+
if ($e->getResponse()->getStatus() == 404) {
57+
throw new NotFoundException("Repository '" . $name . "' does not exist.");
58+
}
59+
throw $e;
60+
}
61+
$data = $response->getData();
62+
return $data[$name];
63+
}
64+
65+
/**
66+
* Retrieve all repository records
67+
* @return array
68+
*/
69+
public function getAllRepositories()
70+
{
71+
return $this->request("_all")->getData();
72+
}
73+
74+
/**
75+
* Create a new snapshot
76+
* @param string $repository the name of the repository in which this snapshot should be stored
77+
* @param string $name the name of this snapshot
78+
* @param array $options optional settings for this snapshot
79+
* @param bool $waitForCompletion if true, the request will not return until the snapshot operation is complete
80+
* @return Response
81+
*/
82+
public function createSnapshot($repository, $name, $options = array(), $waitForCompletion = false)
83+
{
84+
return $this->request($repository . '/' . $name, Request::PUT, $options, array('wait_for_completion' => $waitForCompletion));
85+
}
86+
87+
/**
88+
* Retrieve data regarding a specific snapshot
89+
* @param string $repository the name of the repository from which to retrieve the snapshot
90+
* @param string $name the name of the desired snapshot
91+
* @throws Exception\ResponseException
92+
* @throws Exception\NotFoundException
93+
* @return array
94+
*/
95+
public function getSnapshot($repository, $name)
96+
{
97+
try {
98+
$response = $this->request($repository . "/" . $name);
99+
} catch (ResponseException $e) {
100+
if ($e->getResponse()->getStatus() == 404) {
101+
throw new NotFoundException("Snapshot '" . $name . "' does not exist in repository '" . $repository . "'.");
102+
}
103+
throw $e;
104+
}
105+
$data = $response->getData();
106+
return $data['snapshots'][0];
107+
}
108+
109+
/**
110+
* Retrieve data regarding all snapshots in the given repository
111+
* @param string $repository the repository name
112+
* @return array
113+
*/
114+
public function getAllSnapshots($repository)
115+
{
116+
return $this->request($repository . "/_all")->getData();
117+
}
118+
119+
/**
120+
* Delete a snapshot
121+
* @param string $repository the repository in which the snapshot resides
122+
* @param string $name the name of the snapshot to be deleted
123+
* @return Response
124+
*/
125+
public function deleteSnapshot($repository, $name)
126+
{
127+
return $this->request($repository . "/" . $name, Request::DELETE);
128+
}
129+
130+
/**
131+
* Restore a snapshot
132+
* @param string $repository the name of the repository
133+
* @param string $name the name of the snapshot
134+
* @param array $options options for the restore operation
135+
* @param bool $waitForCompletion if true, the request will not return until the restore operation is complete
136+
* @return Response
137+
*/
138+
public function restoreSnapshot($repository, $name, $options = array(), $waitForCompletion = false)
139+
{
140+
return $this->request($repository . "/" . $name . "/_restore", Request::POST, $options, array("wait_for_completion" => $waitForCompletion));
141+
}
142+
143+
/**
144+
* Perform a snapshot request
145+
* @param string $path the URL
146+
* @param string $method the HTTP method
147+
* @param array $data request body data
148+
* @param array $query query string parameters
149+
* @return Response
150+
*/
151+
public function request($path, $method = Request::GET, $data = array(), array $query = array())
152+
{
153+
return $this->_client->request("/_snapshot/" . $path, $method, $data, $query);
154+
}
155+
}
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
namespace Elastica\Test;
4+
5+
6+
use Elastica\Document;
7+
use Elastica\Index;
8+
use Elastica\Snapshot;
9+
10+
class SnapshotTest extends Base
11+
{
12+
/**
13+
* @var Snapshot
14+
*/
15+
protected $_snapshot;
16+
17+
/**
18+
* @var Index
19+
*/
20+
protected $_index;
21+
22+
/**
23+
* @var Document[]
24+
*/
25+
protected $_docs;
26+
27+
protected function setUp()
28+
{
29+
parent::setUp();
30+
$this->_snapshot = new Snapshot($this->_getClient());
31+
32+
$this->_index = $this->_createIndex("test_snapshot");
33+
$this->_docs = array(
34+
new Document("1", array("city" => "San Diego")),
35+
new Document("2", array("city" => "San Luis Obispo")),
36+
new Document("3", array("city" => "San Francisco")),
37+
);
38+
$this->_index->getType("test")->addDocuments($this->_docs);
39+
$this->_index->refresh();
40+
}
41+
42+
protected function tearDown()
43+
{
44+
parent::tearDown();
45+
$this->_index->delete();
46+
}
47+
48+
public function testRegisterRepository()
49+
{
50+
$name = "test_register";
51+
$location = "/tmp/test_register";
52+
53+
$response = $this->_snapshot->registerRepository($name, "fs", array("location" => $location));
54+
$this->assertTrue($response->isOk());
55+
56+
$response = $this->_snapshot->getRepository($name);
57+
$this->assertEquals($location, $response["settings"]["location"]);
58+
59+
// attempt to retrieve a repository which does not exist
60+
$this->setExpectedException('Elastica\Exception\NotFoundException');
61+
$this->_snapshot->getRepository("foobar");
62+
}
63+
64+
public function testSnapshotAndRestore()
65+
{
66+
$repositoryName = "test_repository";
67+
$location = "/tmp/{$repositoryName}";
68+
69+
// register the repository
70+
$response = $this->_snapshot->registerRepository($repositoryName, "fs", array("location" => $location));
71+
$this->assertTrue($response->isOk());
72+
73+
// create a snapshot of our test index
74+
$snapshotName = "test_snapshot_1";
75+
$response = $this->_snapshot->createSnapshot($repositoryName, $snapshotName, array("indices" => $this->_index->getName()), true);
76+
77+
// ensure that the snapshot was created properly
78+
$this->assertTrue($response->isOk());
79+
$this->assertArrayHasKey("snapshot", $response->getData());
80+
$data = $response->getData();
81+
$this->assertContains($this->_index->getName(), $data["snapshot"]["indices"]);
82+
$this->assertEquals(1, sizeof($data["snapshot"]["indices"])); // only the specified index should be present
83+
$this->assertEquals($snapshotName, $data["snapshot"]["snapshot"]);
84+
85+
// retrieve data regarding the snapshot
86+
$response = $this->_snapshot->getSnapshot($repositoryName, $snapshotName);
87+
$this->assertContains($this->_index->getName(), $response["indices"]);
88+
89+
// delete our test index
90+
$this->_index->delete();
91+
92+
// restore the index from our snapshot
93+
$response = $this->_snapshot->restoreSnapshot($repositoryName, $snapshotName, array(), true);
94+
$this->assertTrue($response->isOk());
95+
96+
$this->_index->refresh();
97+
$this->_index->optimize();
98+
99+
// ensure that the index has been restored
100+
$count = $this->_index->getType("test")->count();
101+
$this->assertEquals(sizeof($this->_docs), $count);
102+
103+
// delete the snapshot
104+
$response = $this->_snapshot->deleteSnapshot($repositoryName, $snapshotName);
105+
$this->assertTrue($response->isOk());
106+
107+
// ensure that the snapshot has been deleted
108+
$this->setExpectedException('Elastica\Exception\NotFoundException');
109+
$this->_snapshot->getSnapshot($repositoryName, $snapshotName);
110+
}
111+
}
112+

0 commit comments

Comments
 (0)