Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ A PHP SDK for integrating with the [Veeam Service Provider Console (VSPC)](https

## Features
- Guzzle-based HTTP client preconfigured for the VSPC REST endpoints.
- Repository classes mirroring the API tags (Authentication, Companies, Backup Servers, and more).
- Repository classes mirroring the API tags (Alarms, Authentication, Backup Agents, Backup Policies, Backup Server Jobs, Backup Servers, Cloud Connect, Companies, Licensing, Locations, Management Agents, Misc, Organizations, Provider, Pulse, Microsoft 365, and more).
- Fluent payload builders to compose request bodies for complex operations.
- `GenericPayload` helper to quickly serialize ad-hoc request bodies when a dedicated builder is not required.
- Helpers for filters, pagination, and query parameters.
- Returns PSR-7 responses or decoded JSON payloads for convenience.

Expand Down Expand Up @@ -66,6 +67,23 @@ $response = $client->jsonResponse($request);

Repositories accept optional filters and query parameters when executed through `VeeamSPCClient::send()` or `VeeamSPCClient::jsonResponse()`. You can build complex filters using `Filter` and `FilterCollection` helpers located under `Shellrent\VeeamVspcApiClient\Support`.

### Send an Ad-hoc JSON Body
When an endpoint requires a request body that does not yet have a dedicated payload builder, you can rely on the `GenericPayload` helper. Pass an array (automatically encoded as JSON) or a raw string together with the desired content type.

```php
use Shellrent\VeeamVspcApiClient\Payloads\GenericPayload;
use Shellrent\VeeamVspcApiClient\Repositories\BackupPolicyRepository;

$payload = new GenericPayload([
'Name' => 'My Custom Policy',
'Description' => 'Created through the SDK',
]);

$backupPolicyRepository = new BackupPolicyRepository();
$request = $backupPolicyRepository->createWindowsBackupPolicy($payload);
$response = $client->jsonResponse($request);
```

## OpenAPI Specification
The official VSPC OpenAPI definition used to generate the SDK is stored in [`openapi/3.5.1/vspc-api.json`](openapi/3.5.1/vspc-api.json). Refer to it for a complete list of available operations, parameters, and payload schemas.

Expand Down
22 changes: 22 additions & 0 deletions src/Payloads/GenericPayload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Shellrent\VeeamVspcApiClient\Payloads;

class GenericPayload implements Payload {
private $body;

private string $contentType;

public function __construct( $body, string $contentType = 'application/json' ) {
$this->body = is_array( $body ) ? json_encode( $body ) : $body;
$this->contentType = $contentType;
}

public function getBody() {
return $this->body;
}

public function getContentType(): string {
return $this->contentType;
}
}
24 changes: 23 additions & 1 deletion src/Payloads/ModifyLicenseManagedInVCSPPulsePayload.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@
class ModifyLicenseManagedInVCSPPulsePayload implements Payload {
protected string $AssignedCompanyUid;

protected array $Modifiers;
protected array $Modifiers = [];

/**
* @var array<int, array<string, mixed>>
*/
protected array $Workloads = [];

public function getBody() {
$body = $this->Modifiers;

foreach ( $this->Workloads as $workload ) {
$body[] = [
'value' => $workload['count'],
'path' => '/workloads/' . $workload['index'] . '/count',
'op' => 'replace'
];
}

return json_encode( $body );
}

Expand All @@ -23,6 +36,15 @@ public function assignedCompanyUid( string $companyUid ) {
return $this;
}

public function addWorkloadCount( $workloadIndex, $count ) {
$this->Workloads[] = [
'index' => $workloadIndex,
'count' => $count,
];

return $this;
}

public function expirationDate( string $isoDate ): ModifyLicenseManagedInVCSPPulsePayload {
$this->Modifiers[] = [
'value' => $isoDate,
Expand Down
147 changes: 126 additions & 21 deletions src/Repositories/AlarmRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,141 @@

namespace Shellrent\VeeamVspcApiClient\Repositories;

use Shellrent\VeeamVspcApiClient\Support\CreateDeleteRequest;
use Shellrent\VeeamVspcApiClient\Support\CreateGetRequest;
use Shellrent\VeeamVspcApiClient\Support\CreatePostRequest;
use Shellrent\VeeamVspcApiClient\Support\RequestBuilder;

class AlarmRepository implements Repository {
use CreateDeleteRequest;
use CreateGetRequest;

use CreatePostRequest;

public function getBaseRoute(): string {
return 'alarms';
}

public function getAllTriggeredAlarms(): RequestBuilder {
return $this->createGetRequest( '/active' );
}

public function getAllAlarmTemplates(): RequestBuilder {
return $this->createGetRequest( '/templates' );
}

public function postResolveAlarm( string $alarmUid, string $comment = ' ' ): RequestBuilder {
return $this->createPostRequest( sprintf( '/active/%s/resolve', $alarmUid ) )
->query( [
'comment' => $comment,
'resolveOnClients' => 'true',
] );
}

public function getAlarmStatusChanges( string $alarmUid ): RequestBuilder {
return $this->createGetRequest( sprintf( '/templates/%s/events', $alarmUid ) );

/**
* Get All Triggered Alarms Returns collection resource representation of all Veeam Service Provider Console triggered alarms.
* Path: /alarms/active
*/
public function getActiveAlarms(array $query = []): RequestBuilder {
$request = $this->createGetRequest('/active');
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Delete Triggered Alarm Deletes a triggered alarm with the specified UID.
* Path: /alarms/active/{activeAlarmUid}
*/
public function deleteActiveAlarm(string $activeAlarmUid): RequestBuilder {
return $this->createDeleteRequest(sprintf( '/active/%s', $activeAlarmUid ));
}

/**
* Get Triggered Alarm Returns a resource representation of a triggered alarm with the specified UID.
* Path: /alarms/active/{activeAlarmUid}
*/
public function getActiveAlarm(string $activeAlarmUid, array $query = []): RequestBuilder {
$request = $this->createGetRequest(sprintf( '/active/%s', $activeAlarmUid ));
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Acknowledge Triggered Alarm Assigns the Acknowledged status to a triggered alarm with the specified UID.
* Path: /alarms/active/{activeAlarmUid}/acknowledge
*/
public function acknowledgeActiveAlarm(string $activeAlarmUid, array $query = []): RequestBuilder {
$request = $this->createPostRequest(sprintf( '/active/%s/acknowledge', $activeAlarmUid ));
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Get Triggered Alarm History Returns a collection resource representation of all status changes of a triggered alarm with the specified UID in chronological order.
* Path: /alarms/active/{activeAlarmUid}/history
*/
public function getActiveAlarmHistory(string $activeAlarmUid, array $query = []): RequestBuilder {
$request = $this->createGetRequest(sprintf( '/active/%s/history', $activeAlarmUid ));
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Resolve Triggered Alarm Resolves a triggered alarm with the specified UID.
* Path: /alarms/active/{activeAlarmUid}/resolve
*/
public function resolveActiveAlarm(string $activeAlarmUid, array $query = []): RequestBuilder {
$request = $this->createPostRequest(sprintf( '/active/%s/resolve', $activeAlarmUid ));
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Get All Alarm Templates Returns a collection resource representation of all Veeam Service Provider Console alarm templates.
* Path: /alarms/templates
*/
public function getAlarms(array $query = []): RequestBuilder {
$request = $this->createGetRequest('/templates');
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Delete Alarm Template Deletes an alarm template with the specified UID.
* Path: /alarms/templates/{alarmUid}
*/
public function deleteAlarm(string $alarmUid): RequestBuilder {
return $this->createDeleteRequest(sprintf( '/templates/%s', $alarmUid ));
}

/**
* Get Alarm Template Returns a resource representation of an alarm template with the specified UID.
* Path: /alarms/templates/{alarmUid}
*/
public function getAlarm(string $alarmUid, array $query = []): RequestBuilder {
$request = $this->createGetRequest(sprintf( '/templates/%s', $alarmUid ));
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Clone Alarm Template Creates a clone of an alarm template with the specified UID.
* Path: /alarms/templates/{alarmUid}/clone
*/
public function cloneAlarm(string $alarmUid, array $query = []): RequestBuilder {
$request = $this->createPostRequest(sprintf( '/templates/%s/clone', $alarmUid ));
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Get Alarm Status Changes Returns all status changes of a triggered alarm with the specified template UID.
* Path: /alarms/templates/{alarmUid}/events
*/
public function getActiveAlarmsByAlarm(string $alarmUid, array $query = []): RequestBuilder {
$request = $this->createGetRequest(sprintf( '/templates/%s/events', $alarmUid ));
if ($query !== []) {
$request->query($query);
}
return $request;
}
}
118 changes: 113 additions & 5 deletions src/Repositories/AuthenticationRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,126 @@

namespace Shellrent\VeeamVspcApiClient\Repositories;

use Shellrent\VeeamVspcApiClient\Payloads\OAuthPayload;
use Shellrent\VeeamVspcApiClient\Payloads\Payload;
use Shellrent\VeeamVspcApiClient\Support\CreateGetRequest;
use Shellrent\VeeamVspcApiClient\Support\CreatePatchRequest;
use Shellrent\VeeamVspcApiClient\Support\CreatePostRequest;
use Shellrent\VeeamVspcApiClient\Support\RequestBuilder;

class AuthenticationRepository implements Repository {
use CreateGetRequest;
use CreatePatchRequest;
use CreatePostRequest;

public function getBaseRoute(): string {
return '';
}

public function postOAuthAuthentication( OAuthPayload $payload ): RequestBuilder {
return $this->createPostRequest( '/token', $payload );

/**
* Obtain Tokens for Decrypted Challenge Issues access and refresh tokens in response to a decrypted challenge. > Operation is deprecated. We recommend to authorize using the `/token` endpoint.
* Path: /authentication/asymmetricalgorithm
*/
public function asymmetricAlgorithmCompleteChallenge(?Payload $payload = null, array $query = []): RequestBuilder {
$request = $this->createPatchRequest('/authentication/asymmetricalgorithm', $payload);
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Generate Asymmetric Authentication Challenge Generates a decryption challenge for the specified public key. The challenge must be decrypted in 30 seconds. > Operation is deprecated. We recommend to authorize using the `/users/{userUid}/logins/apikey` or `/token` endpoint.
* Path: /authentication/asymmetricalgorithm
*/
public function asymmetricAlgorithmChallenge(?Payload $payload = null, array $query = []): RequestBuilder {
$request = $this->createPostRequest('/authentication/asymmetricalgorithm', $payload);
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Obtain RSA Keys Issues an RSA key pair. > You can specify the key size if needed.
* Path: /authentication/keys/rsa
*/
public function generateNewRsaKeyPair(array $query = []): RequestBuilder {
$request = $this->createGetRequest('/authentication/keys/rsa');
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Issues a PKCS#12 container with an RSA private key and an X.509 certificate.
* Path: /authentication/keys/rsa-pkcs12
*/
public function generateNewPkcs12KeyPair(array $query = []): RequestBuilder {
$request = $this->createGetRequest('/authentication/keys/rsa-pkcs12');
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Decrypts an encrypted PKCS#12 container. > If container does not include private key the server will return an error with the `1210` code.
* Path: /authentication/keys/rsa-pkcs12/decrypt
*/
public function decryptPkcs12Container(?Payload $payload = null, array $query = []): RequestBuilder {
$request = $this->createPostRequest('/authentication/keys/rsa-pkcs12/decrypt', $payload);
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Obtain TOTP Secret Issues a TOTP secret and a URL-encoded secret.
* Path: /authentication/keys/totp-secret
*/
public function generateTotpSecret(array $query = []): RequestBuilder {
$request = $this->createGetRequest('/authentication/keys/totp-secret');
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Obtain New Pair of Tokens Returns access and refresh tokens in response to refresh token. > Operation is deprecated. We recommend to authorize using the `/token` endpoint.
* Path: /authentication/refresh
*/
public function refreshTokenAuthenticate(?Payload $payload = null, array $query = []): RequestBuilder {
$request = $this->createPostRequest('/authentication/refresh', $payload);
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* Authenticate with User Name and Password Issues access and refresh tokens for the specified user name and password. > Operation is deprecated. We recommend to authorize using the `/token` endpoint.
* Path: /authentication/usernamepassword
*/
public function usernamePasswordAuthenticate(?Payload $payload = null, array $query = []): RequestBuilder {
$request = $this->createPostRequest('/authentication/usernamepassword', $payload);
if ($query !== []) {
$request->query($query);
}
return $request;
}

/**
* OAuth 2.0 Authentication Performs authentication using the OAuth 2.0 Authorization Framework.
* Path: /token
*/
public function oAuth2IssueToken(?Payload $payload = null, array $query = []): RequestBuilder {
$request = $this->createPostRequest('/token', $payload);
if ($query !== []) {
$request->query($query);
}
return $request;
}
}
Loading