Completed
Push — master ( 3eed6d...7635b2 )
by Sebastian
04:09 queued 01:07
created

Redis   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 9
dl 0
loc 198
ccs 56
cts 56
cp 1
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A isDumpCreatedYet() 0 12 3
A setup() 0 13 2
A backup() 0 20 2
A createExecutable() 0 9 1
A getRedisLastSave() 0 6 1
A getLastBackupTime() 0 10 2
A copyDumpToTarget() 0 9 2
A createStatus() 0 4 1
1
<?php
2
namespace phpbu\App\Backup\Source;
3
4
use phpbu\App\Backup\Target;
5
use phpbu\App\Cli\Executable;
6
use phpbu\App\Exception;
7
use phpbu\App\Result;
8
use phpbu\App\Util;
9
10
/**
11
 * Tar source class.
12
 *
13
 * @package    phpbu
14
 * @subpackage Backup
15
 * @author     Sebastian Feldmann <[email protected]>
16
 * @copyright  Sebastian Feldmann <[email protected]>
17
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
18
 * @link       http://phpbu.de/
19
 * @since      Class available since Release 2.1.12
20
 */
21
class Redis extends SimulatorExecutable implements Simulator
22
{
23
    /**
24
     * Executable to handle redis command.
25
     *
26
     * @var \phpbu\App\Cli\Executable\RedisCli
27
     */
28
    protected $executable;
29
30
    /**
31
     * Path to executable.
32
     *
33
     * @var string
34
     */
35
    private $pathToRedisCli;
36
37
    /**
38
     * Time to wait for the dump to finish, 45 seconds by default
39
     *
40
     * @var integer
41
     */
42
    private $timeout;
43
44
    /**
45
     * Host to backup
46
     *
47
     * @var string
48
     */
49
    private $host;
50
51
    /**
52
     * Port to connect to
53
     *
54
     * @var int
55
     */
56
    private $port;
57
58
    /**
59
     * Password for authentication
60
     *
61
     * @var string
62
     */
63
    private $password;
64
65
    /**
66
     * Path to the redis rdb directory, for Debian it's /var/lib/redis/{PORT}/dump.rdb
67
     *
68
     * @var string
69
     */
70
    private $pathToRedisData;
71
72
    /**
73
     * Setup.
74
     *
75
     * @see    \phpbu\App\Backup\Source
76
     * @param  array $conf
77
     * @throws \phpbu\App\Exception
78
     */
79 7
    public function setup(array $conf = [])
80
    {
81 7
        $this->pathToRedisCli  = Util\Arr::getValue($conf, 'pathToRedisCli', '');
82 7
        $this->pathToRedisData = Util\Arr::getValue($conf, 'pathToRedisData', '');
83 7
        $this->timeout         = Util\Arr::getValue($conf, 'timeout', 45);
84 7
        $this->host            = Util\Arr::getValue($conf, 'host', '');
85 7
        $this->port            = Util\Arr::getValue($conf, 'port', 0);
86 7
        $this->password        = Util\Arr::getValue($conf, 'password', '');
87
88 7
        if (empty($this->pathToRedisData)) {
89 1
            throw new Exception('pathToRedisData option is mandatory');
90
        }
91 6
    }
92
93
    /**
94
     * Execute the backup.
95
     *
96
     * @see    \phpbu\App\Backup\Source
97
     * @param  \phpbu\App\Backup\Target $target
98
     * @param  \phpbu\App\Result        $result
99
     * @return \phpbu\App\Backup\Source\Status
100
     * @throws \phpbu\App\Exception
101
     */
102 5
    public function backup(Target $target, Result $result) : Status
103
    {
104
        // set uncompressed default MIME type
105 5
        $target->setMimeType('application/octet-stream');
106
107 5
        $redisSave = $this->getExecutable($target);
108 5
        $redisLast = $this->getRedisLastSave($this->executable);
109
110 5
        $lastBackupTimestamp = $this->getLastBackupTime($redisLast);
111 4
        $saveResult          = $this->runCommand($redisSave);
112 4
        $result->debug($this->getExecutable($target)->getCommandPrintable());
113 4
        if (!$saveResult->isSuccessful()) {
114 1
            throw new Exception('redis-cli BGSAVE failed:' . $saveResult->getStdErr());
115
        }
116
        // check if the save process is finished
117 3
        $this->isDumpCreatedYet($lastBackupTimestamp, $redisLast);
118 2
        $this->copyDumpToTarget($target);
119
120 1
        return $this->createStatus($target);
121
    }
122
123
    /**
124
     * Setup the Executable to run the 'tar' command.
125
     *
126
     * @param  \phpbu\App\Backup\Target
127
     * @return \phpbu\App\Cli\Executable
128
     */
129 6
    protected function createExecutable(Target $target) : Executable
130
    {
131 6
        $executable = new Executable\RedisCli($this->pathToRedisCli);
132 6
        $executable->backup()
133 6
                   ->useHost($this->host)
134 6
                   ->usePort($this->port)
135 6
                   ->usePassword($this->password);
136 6
        return $executable;
137
    }
138
139
    /**
140
     * Creates a RedisLastSave command from a RedisSave command.
141
     *
142
     * @param  \phpbu\App\Cli\Executable\RedisCli $redis
143
     * @return \phpbu\App\Cli\Executable\RedisCli
144
     */
145 5
    public function getRedisLastSave(Executable\RedisCli $redis) : Executable\RedisCli
146
    {
147 5
        $redisLast = clone($redis);
148 5
        $redisLast->lastBackupTime();
149 5
        return $redisLast;
150
    }
151
152
    /**
153
     * Return last successful save timestamp.
154
     *
155
     * @param  \phpbu\App\Cli\Executable\RedisCli $redis
156
     * @return int
157
     * @throws \phpbu\App\Exception
158
     */
159 5
    private function getLastBackupTime(Executable\RedisCli $redis) : int
160
    {
161 5
        $result  = $this->runCommand($redis);
162 5
        $output  = $result->getStdOut();
163 5
        $matches = [];
164 5
        if (!preg_match('#(\(integer\) )?([0-9]+)#i', $output, $matches)) {
165 1
            throw new Exception('invalid redis-cli LASTSAVE output');
166
        }
167 4
        return (int) $matches[2];
168
    }
169
170
    /**
171
     * Check the dump date and return true if BGSAVE is finished.
172
     *
173
     * @param  int                                $lastTimestamp
174
     * @param  \phpbu\App\Cli\Executable\RedisCli $redis
175
     * @return bool
176
     * @throws \phpbu\App\Exception
177
     */
178 3
    private function isDumpCreatedYet($lastTimestamp, $redis) : bool
179
    {
180 3
        $i = 0;
181 3
        while ($this->getLastBackupTime($redis) <= $lastTimestamp) {
182 1
            if ($i > $this->timeout) {
183 1
                throw new Exception('redis-cli BGSAVE is taking to long, increase timeout');
184
            }
185 1
            $i++;
186 1
            sleep(1);
187
        }
188 2
        return true;
189
    }
190
191
    /**
192
     * Copy the redis RDB file to its backup location.
193
     *
194
     * @param  \phpbu\App\Backup\Target $target
195
     * @return string
196
     * @throws \phpbu\App\Exception
197
     */
198 2
    private function copyDumpToTarget(Target $target) : string
199
    {
200 2
        if (!file_exists($this->pathToRedisData)) {
201 1
            throw new Exception('Redis data not found at: \'' . $this->pathToRedisCli . '\'');
202
        }
203 1
        $targetFile = $target->getPathnamePlain();
204 1
        copy($this->pathToRedisData, $targetFile);
205 1
        return $targetFile;
206
    }
207
208
    /**
209
     * Create backup status.
210
     *
211
     * @param  \phpbu\App\Backup\Target
212
     * @return \phpbu\App\Backup\Source\Status
213
     */
214 1
    protected function createStatus(Target $target) : Status
215
    {
216 1
        return Status::create()->uncompressedFile($target->getPathnamePlain());
217
    }
218
}
219