php-opencloud/openstack
PHP OpenStack SDK for connecting to OpenStack APIs from PHP. Simple, idiomatic clients with support for multiple OpenStack services and versions, semantic versioning, and active docs and tests. Requires PHP 7.2.5+ and ext-curl.
## Getting Started
### Minimal Setup
1. **Install the package**:
```bash
composer require php-opencloud/openstack
Configure credentials (via environment variables or config file):
use OpenStack\OpenStack;
$connection = OpenStack::connection([
'region' => 'RegionOne',
'auth' => [
'authUrl' => 'https://keystone.example.com:5000/v3',
'username' => 'your-username',
'password' => 'your-password',
'project' => 'your-project',
'userDomainName' => 'Default',
'projectDomainName' => 'Default',
],
]);
First use case: List servers (Compute):
$servers = $connection->compute()->servers()->all();
foreach ($servers as $server) {
echo $server->name . "\n";
}
/samples/ directory for real-world examples (e.g., samples/compute/create_server.php)./COVERAGE.md for supported OpenStack services/versions (e.g., Nova, Cinder, Swift).Api.php files (e.g., src/Compute/v2/Api.php) for operation details.OpenStack::connection() with a config array or ConnectionInterface implementation.$connection = OpenStack::connection([
'region' => 'RegionOne',
'auth' => ['authUrl' => '...', 'username' => '...', ...],
]);
.env and use config('services.openstack').compute()->servers()) and use fluent interfaces.// Create a server
$server = $connection->compute()->servers()->create([
'name' => 'web-server',
'imageRef' => 'ubuntu-22.04',
'flavorRef' => 'm1.small',
'networks' => [['uuid' => 'net-uuid']],
]);
// List servers with pagination
$servers = $connection->compute()->servers()->all();
foreach ($servers as $server) {
echo $server->id . ": " . $server->status . "\n";
}
createLargeObject() for files >10GB with customizable segment indexing.$container = $connection->objectStore()->containers()->find('my-container');
$largeObject = $container->createLargeObject('huge-file.dat', [
'segmentIndexFormat' => 'custom-{index}.part',
]);
$largeObject->uploadFromFile('/path/to/huge-file.dat');
HasWaiterTrait (e.g., Compute::Image) for long-running tasks.$image = $connection->compute()->images()->find('image-uuid');
$image->waitFor('active');
OpenStack\Common\Exception\ServiceException and use errorVerbosity for debugging.try {
$server->delete();
} catch (ServiceException $e) {
if ($e->getErrorVerbosity() === ServiceException::VERBOSITY_DEBUG) {
echo $e->getDebugInfo();
}
}
applicationCredentials or Token::validate() for zero-trust workflows.// Application credentials
$connection = OpenStack::connection([
'auth' => [
'authUrl' => '...',
'applicationCredentialId' => 'cred-uuid',
'applicationCredentialSecret' => 'secret',
],
]);
// Token validation
$token = $connection->identity()->tokens()->find('token-uuid');
if ($token->validate()) {
// Proceed
}
use OpenStack\OpenStack;
class OpenStackServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton('openstack', function ($app) {
return OpenStack::connection(config('services.openstack'));
});
}
}
// app/Facades/OpenStack.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class OpenStack extends Facade {
protected static function getFacadeAccessor() {
return 'openstack';
}
}
// config/services.php
'openstack' => [
'region' => env('OPENSTACK_REGION'),
'auth' => [
'authUrl' => env('OPENSTACK_AUTH_URL'),
'username' => env('OPENSTACK_USERNAME'),
'password' => env('OPENSTACK_PASSWORD'),
'project' => env('OPENSTACK_PROJECT'),
],
],
Deprecated Keystone v2:
authUrl to include /v3 (e.g., https://keystone.example.com/v3).Token Expiry:
Token::validate() or handle 401 Unauthorized errors gracefully.$connection->identity()->tokens()->refresh();
Large Object Segments:
segment-{index}) may conflict with existing files.segmentIndexFormat (e.g., custom-{index}.part).Case-Sensitive Headers (Swift):
X-Object-Meta-* consistently.Guzzle Promises:
GuzzleHttp\Promise\Utils::all (not GuzzleHttp\Promise\all).guzzlehttp/promises>=2.0 is installed.Server Groups (Nova):
soft-anti-affinity).Compute::ServerGroup::create() for policy constraints.$connection->setErrorVerbosity(OpenStack\Common\Exception\ServiceException::VERBOSITY_DEBUG);
$stack = HandlerStack::create();
$stack->push(Middleware::tap(function ($request) {
\Log::debug('Request:', ['url' => (string) $request->getUri(), 'body' => $request->getBody()]);
}));
$connection->setHandler($stack);
Content-Type) can cause silent failures. Validate with:
$request->getHeaders();
OpenStack\Common\Resource\OperatorResource to add behavior:
class CustomServer extends \OpenStack\Compute\v2\Models\Server {
public function customAction() {
return $this->execute('POST', '/servers/{id}/action', ['os-custom-action' => true]);
}
}
$connection->setHandler(HandlerStack::create([
new Middleware(),
$connection->getHandler(),
]));
OpenStack\Common\Service:
class CustomService extends \OpenStack\Common\Service {
public function customMethod() {
return $this->execute('GET', '/custom-endpoint');
}
}
enumerate() in models for custom pagination:
public function enumerate($limit =
How can I help you explore Laravel packages today?