Completed
Push — master ( b9ed2d...1e16b2 )
by Sebastian
9s
created

Openstack::setup()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4.0058

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 13
cts 14
cp 0.9286
rs 9.2
c 0
b 0
f 0
cc 4
eloc 13
nc 4
nop 1
crap 4.0058
1
<?php
2
namespace phpbu\App\Backup\Sync;
3
4
use GuzzleHttp\Psr7\Stream;
5
use OpenStack\ObjectStore\v1\Service as ObjectStoreService;
6
use GuzzleHttp\Client;
7
use OpenStack\Common\Transport\HandlerStack;
8
use OpenStack\Common\Transport\Utils;
9
use OpenStack\Identity\v2\Service;
10
use phpbu\App\Backup\Target;
11
use phpbu\App\Result;
12
use phpbu\App\Util\Arr;
13
use phpbu\App\Util\Str;
14
15
/**
16
 * OpenStack Swift Sync
17
 *
18
 * @package    phpbu
19
 * @subpackage Backup
20
 * @author     Vitaly Baev <[email protected]>
21
 * @author     Sebastian Feldmann <[email protected]>
22
 * @copyright  Sebastian Feldmann <[email protected]>
23
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
24
 * @link       http://phpbu.de/
25
 * @since      Class available since Release 5.1
26
 */
27
class Openstack implements Simulator
28
{
29
    /**
30
     * OpenStack identify url
31
     *
32
     * @var string
33
     */
34
    protected $authUrl;
35
36
    /**
37
     * OpenStack region
38
     *
39
     * @var string
40
     */
41
    protected $region;
42
43
    /**
44
     * @var string
45
     */
46
    protected $username;
47
48
    /**
49
     * @var string
50
     */
51
    protected $password;
52
53
    /**
54
     * Object Store container name
55
     *
56
     * @var string
57
     */
58
    protected $containerName;
59
60
    /**
61
     * OpenStack service name
62
     *
63
     * @var string
64
     */
65
    protected $serviceName;
66
67
    /**
68
     * Max stream upload size, files over this size have to be uploaded as Dynamic Large Objects
69
     *
70
     * @var int
71
     */
72
    protected $maxStreamUploadSize = 5368709120;
73
74
    /**
75
     * Path where to copy the backup.
76
     *
77
     * @var string
78
     */
79
    protected $path = '';
80
81
    /**
82
     * (non-PHPDoc)
83
     *
84
     * @see    \phpbu\App\Backup\Sync::setup()
85
     * @param  array $config
86
     * @throws \phpbu\App\Backup\Sync\Exception
87
     */
88 9
    public function setup(array $config)
89
    {
90 9
        if (!class_exists('\\OpenStack\\OpenStack')) {
91
            throw new Exception('OpeStack SDK not loaded: use composer to install "php-opencloud/openstack"');
92
        }
93
94
        // check for mandatory options
95 9
        $this->validateConfig($config);
96
97 4
        $this->authUrl       = $config['auth_url'];
98 4
        $this->region        = $config['region'];
99 4
        $this->username      = $config['username'];
100 4
        $this->password      = $config['password'];
101 4
        $this->containerName = $config['container_name'];
102 4
        $this->serviceName   = Arr::getValue($config, 'service_name', 'swift');
103 4
        if (Arr::getValue($config, 'path')) {
104 1
            $this->path = Str::withTrailingSlash(Str::replaceDatePlaceholders($config['path']));
105 1
            $this->path = substr($this->path, 0, 1) == '/' ? substr($this->path, 1) : $this->path;
106
        }
107 4
    }
108
109
    /**
110
     * Make sure all mandatory keys are present in given config.
111
     *
112
     * @param  array $config
113
     * @throws \phpbu\App\Backup\Sync\Exception
114
     */
115 9
    protected function validateConfig(array $config)
116
    {
117 9
        foreach (['auth_url', 'region', 'username', 'password', 'container_name'] as $option) {
118 9
            if (!Arr::isSetAndNotEmptyString($config, $option)) {
119 9
                throw new Exception($option . ' is mandatory');
120
            }
121
        }
122 4
    }
123
124
    /**
125
     * Execute the sync.
126
     *
127
     * @see    \phpbu\App\Backup\Sync::sync()
128
     * @param  \phpbu\App\Backup\Target $target
129
     * @param  \phpbu\App\Result        $result
130
     * @throws \phpbu\App\Backup\Sync\Exception
131
     */
132
    public function sync(Target $target, Result $result)
133
    {
134
        $httpClient = new Client([
135
            'base_uri' => Utils::normalizeUrl($this->authUrl),
136
            'handler'  => HandlerStack::create(),
137
        ]);
138
139
        $options = [
140
            'authUrl'         => $this->authUrl,
141
            'region'          => $this->region,
142
            'username'        => $this->username,
143
            'password'        => $this->password,
144
            'identityService' => Service::factory($httpClient),
145
        ];
146
147
        $openStack = new \OpenStack\OpenStack($options);
148
        $objectStoreService = $openStack->objectStoreV1(['catalogName' => $this->serviceName]);
149
        $container = $this->getContainer($objectStoreService, $result);
150
151
        try {
152
            if ($target->getSize() > $this->maxStreamUploadSize) {
153
                // use Dynamic Large Objects
154
                $uploadOptions = [
155
                    'name'   => $this->getUploadPath($target),
156
                    'stream' => new Stream(fopen($target->getPathname(), 'r')),
157
                ];
158
                $container->createLargeObject($uploadOptions);
159
            } else {
160
                // create an object
161
                $uploadOptions = [
162
                    'name' => $this->getUploadPath($target),
163
                    'content' => file_get_contents($target->getPathname()),
164
                ];
165
                $container->createObject($uploadOptions);
166
            }
167
        } catch (\Exception $e) {
168
            throw new Exception($e->getMessage(), null, $e);
169
        }
170
        $result->debug('upload: done');
171
    }
172
173
    /**
174
     * Simulate the sync execution.
175
     *
176
     * @param \phpbu\App\Backup\Target $target
177
     * @param \phpbu\App\Result        $result
178
     */
179 1
    public function simulate(Target $target, Result $result)
180
    {
181 1
        $result->debug(
182 1
            'sync backup to OpenStack' . PHP_EOL
183 1
            . '  region:   ' . $this->region . PHP_EOL
184 1
            . '  key:      ' . $this->username . PHP_EOL
185 1
            . '  password:    ********' . PHP_EOL
186 1
            . '  container: ' . $this->containerName
187
        );
188 1
    }
189
190
    /**
191
     * @param ObjectStoreService $service
192
     * @return \OpenStack\ObjectStore\v1\Models\Container
193
     * @throws \OpenStack\Common\Error\BadResponseError
194
     */
195
    protected function getContainer(ObjectStoreService $service, Result $result)
196
    {
197
        if (!$service->containerExists($this->containerName)) {
198
            $result->debug('create container');
199
            return $service->createContainer(['name' => $this->containerName]);
200
        }
201
        return $service->getContainer($this->containerName);
202
    }
203
204
    /**
205
     * Get the upload path
206
     *
207
     * @param \phpbu\App\Backup\Target $target
208
     * @return string
209
     */
210 2
    public function getUploadPath(Target $target)
211
    {
212 2
        return $this->path . $target->getFilename();
213
    }
214
}
215