OpenStack PHP and OVH

This post was published 11 months ago. Due to the rapidly evolving world of technology, some concepts may no longer be applicable.

Some time ago I built a setup using Amazon’s S3 and Cloudfront that would allow large file uploads/downloads directly from the an S3 bucket, through a Cloudfront endpoint (which provided both a lower latency and allowed using SSL on a custom domain). I recently came across OVH, and two things caught my attention – low prices and a datacentre in Canada. They run an implementation of the OpenStack API, so it should be fairly easy to get a file uploaded. A few points on the process are illustrated below.

Firstly, I haven’t used PHP for a few years, so I setup a copy of XAMPP on my computer. Get the one with PHPv7. While I don’t usually install software to the root of a drive, I would suggest installing XAMPP to C:\xampp – it is the expected location that makes using some other bits of software a bit easier.

In order to install the PHP OpenStack SDK, you will need to install Composer. The installation should automatically detect your installation of XAMPP find your php executable. If it doesn’t, browse to C:\xampp\php\php.exe.

There appear to be two OpenStack PHP SDK’s – one is under rackspace and the other is under php-opencloud. The Rackspace one has a notice to use the php-opencloud one, since the latter will implement the most recent version of the SDK, and eventually the Rackspace code will simply build upon php-opencloud.

Fair warning, while I got this to work, I frankly wouldn’t recommend it. At this time, php-opencloud is simply put, poorly documented. Moreover, the vast majority of documentation that exists is for the Rackspace implementation and the two do not share the same function names.

To install the SDK, open a command prompt and run
composer require php-opencloud/openstack

The first item that caught me off-guard was the different namespace – most examples use:
use OpenCloud\OpenStack;

The above line applies to the Rackspace implementation. If you are using the php-opencloud implementation, you need:
use OpenStack\OpenStack;

The next error I ran into was that cURL couldn’t verify the SSL certificate of the endpoint I was connecting to. A lot of solutions suggest setting some cURL options to ignore the verification. A better option is to point cURL at an up to date list of certificate authorities. To do so, download the cacert.pem file from https://curl.haxx.se/docs/caextract.html, and update your php.ini file to point cURL to it. The relevant parameter is located under the [curl] block:
curl.cainfo = C:\xampp\cacert.pem

The next issue I came across is that OVH uses IdentityV2. Apparently this has been deprecated since 2013, and the new php-opencloud tried to authenticate against IdentityV3 by default. V3 has a different API, and the authentication fails. The OVH keystone (authentication) endpoint is: https://auth.cloud.ovh.net/v2.0/ – when trying to use the default OpenStack constructor, the result was a 404 error against https://auth.cloud.ovh.net/v2.0/auth/tokens. The correct URL is https://auth.cloud.ovh.net/v2.0/tokens (the former beign the V3 path).

Here is a working example to create an object on OVH using the php-opencloud SDK:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use OpenStack\Identity\v2\Service;
use OpenCloud\Common\Transport\Utils as TransportUtils;
use OpenStack\OpenStack;
 
$authUrl = 'https://auth.cloud.ovh.net/v2.0/';
$username = 'USERNAME'; //ID shown in OVH control panel under OpenStack
$password = 'PASSWORD'; //Password shown in OVH control panel under OpenStack
$tenant_name = 'TENANT_NAME'; //OS_TENANT_NAME after downloading OpenStack config/RC file
$swiftUrl = 'SWIFT_URL'; //API Endpoint you get after logging into OpenStack/Horizon. Under Access and Security > API Access
$region = 'BHS1'; //The region - others are GRA1 and SBG1
 
$container_name = 'CONTAINER_NAME'; //Give your container a name
 
$httpClient = new Client([
    'base_uri' => TransportUtils::normalizeUrl($authUrl),
    'handler'  => HandlerStack::create(),
]);
 
$options = [
    'authUrl'         => $authUrl,
    'region'          => $region,
    'username'        => $username,
    'password'        => $password,
    'tenantName'      => $tenant_name,
    'identityService' => Service::factory($httpClient),
];
$openstack = new OpenStack($options);
 
$service = $openstack->objectStoreV1();
 
//Uncomment the next block if you want to create a container
/*$container = $service->createContainer([
    'name' => $container_name
]);*/
 
//List all the containers you have
foreach ($service->listContainers() as $container) {
printf("%s container has %d objects and %d bytes",
    $container->name, $container->objectCount, $container->bytesUsed);
}
 
 
$container = $service->getContainer($container_name);
 
// Display the name of all objects in the container
foreach ($container->listObjects() as $object) {
   printf("Object name: %s\n", $object->getName());
}
 
//Uncomment the next block if you want to create an object
 
/*$object = $container->createObject([
    'name'    => 'example.txt',
    'content' => 'This is some sample text',
]);*/
 
?>

End result, I switched to the Rackspace codebase.

Leave a Reply

Your email address will not be published. Required fields are marked *