Skip to content

Commit aa085b2

Browse files
committed
v0.1
0 parents  commit aa085b2

File tree

13 files changed

+626
-0
lines changed

13 files changed

+626
-0
lines changed

.env-sample

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
API_URL="portainer.domain.tld:9443"
2+
USERNAME="portainer_user"
3+
PASSWORD="password"
4+
IGNORE_SSL=false

README.md

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Portainer PHP API
2+
3+
Portainer PHP API client
4+
For the full API documentation implemented, please take a look at [https://app.swaggerhub.com/apis/portainer/portainer-ce/2.21.4#/](https://app.swaggerhub.com/apis/portainer/portainer-ce/2.21.4#/)
5+
6+
## Supported endpoint groups
7+
8+
- Auth
9+
- Backup
10+
- CustomTemplates
11+
- Docker
12+
13+
## Installation
14+
15+
Download the package using composer:
16+
17+
```bash
18+
19+
composer require ente/portainer-php-api
20+
21+
```
22+
23+
Then configure .env file with the following variables:
24+
25+
- API_URL (e.g. `localhost:9443`)
26+
- USERNAME
27+
- PASSWORD
28+
- IGNORE_SSL (currently all requests are made with `verify` set to `false`)
29+
30+
## Usage
31+
32+
```php
33+
require_once __DIR__ . "/vendor/autoload.php";
34+
use Portainer\Portainer;
35+
$portainer = new Portainer(__DIR__, ".env", "username", "password", "https://yourhost:9443");
36+
37+
echo var_dump($portainer->customTemplates()->list()); // array containing custom templates
38+
39+
```

composer.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "ente/portainer-php-api",
3+
"type": "library",
4+
"license": "GPL-3.0-only",
5+
"version": "0.1",
6+
"description": "A PHP API client for Portainer CE",
7+
"authors": [
8+
{
9+
"name": "Ente",
10+
"homepage": "https://openducks.org",
11+
"email": "[email protected]"
12+
}
13+
],
14+
15+
"require": {
16+
"php": ">=8.0",
17+
"vlucas/phpdotenv": "5.6.1",
18+
"mirazmac/dotenvwriter": "^0.4.0"
19+
},
20+
"autoload": {
21+
"files": [
22+
"src/Portainer.php"
23+
]
24+
}
25+
}

src/Endpoints/Auth/Auth.php

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
namespace Portainer\Endpoints;
3+
use Portainer\Endpoints\Auth\oAuth;
4+
class Auth {
5+
public \Portainer\Portainer $portainer;
6+
7+
private $oauth;
8+
9+
public function __construct(\Portainer\Portainer $portainer){
10+
$this->portainer = $portainer;
11+
$this->loader();
12+
}
13+
14+
public function loader(){
15+
require_once __DIR__ . "/oAuth.php";
16+
}
17+
18+
public function auth($username, $password){
19+
$response = $this->portainer->sendRequest(["Username" => $username, "Password" => $password], "auth");
20+
if($response["jwt"]){
21+
return $response["jwt"];
22+
} else {
23+
return false;
24+
}
25+
}
26+
27+
public function logout(){
28+
$response = $this->portainer->sendRequest([], "auth/logout");
29+
return (bool)$response;
30+
}
31+
32+
public function oauth(){
33+
if($this->oauth) $this->oauth = new oAuth($this->portainer);
34+
return $this->oauth;
35+
}
36+
}

src/Endpoints/Auth/oAuth.php

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
namespace Portainer\Endpoints\Auth;
3+
class oAuth {
4+
public \Portainer\Portainer $portainer;
5+
6+
public function __construct(\Portainer\Portainer $portainer){
7+
$this->portainer = $portainer;
8+
}
9+
10+
public function validate(string $code){
11+
$response = $this->portainer->sendRequest(["code" => $code], "auth/validate");
12+
if($response["jwt"]){
13+
return $response["jwt"];
14+
} else {
15+
return false;
16+
}
17+
18+
}
19+
}

src/Endpoints/Backup/Backup.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
namespace Portainer\Endpoints;
3+
class Backup {
4+
private \Portainer\Portainer $portainer;
5+
6+
public function __construct(\Portainer\Portainer $portainer){
7+
$this->portainer = $portainer;
8+
}
9+
10+
/**
11+
* `backup()` - Create a backup of the Portainer instance
12+
* @param string $password Password to encrypt the backup
13+
* @return bool|string Returns the backup file path or false
14+
* @note Using this function may cause high memory usage (around ~300MB, depending on the size of your Portainer instance)
15+
*/
16+
public function backup(string $password){
17+
$response = $this->portainer->downloadFile("backup", false, ["password" => $password]);
18+
if(!empty($response)){
19+
return $response;
20+
} else {
21+
return false;
22+
}
23+
}
24+
25+
public function restore(){
26+
// not yet implemented
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
namespace Portainer\Endpoints;
3+
class CustomTemplates {
4+
private \Portainer\Portainer $portainer;
5+
6+
public function __construct(\Portainer\Portainer $portainer){
7+
$this->portainer = $portainer;
8+
}
9+
10+
public function list(){
11+
$response = $this->portainer->sendRequest([], "custom_templates", "GET");
12+
if(isset($response[0])){
13+
return $response;
14+
} else {
15+
return false;
16+
}
17+
}
18+
19+
public function delete(int $id){
20+
$response = $this->portainer->sendRequest([], "custom_templates/$id", "DELETE");
21+
return !$response["error"];
22+
}
23+
24+
public function get(int $id){
25+
$response = $this->portainer->sendRequest([], "custom_templates/$id", "GET");
26+
if(isset($response["Id"])){
27+
return $response;
28+
} else {
29+
return false;
30+
}
31+
}
32+
33+
public function update(array $data, int $id){
34+
$response = $this->portainer->sendRequest($data, "custom_templates/$id", "PUT", false, true);
35+
return !$response["Id"];
36+
}
37+
38+
public function getStackFile(int $id){
39+
$response = $this->portainer->sendRequest([], "custom_templates/$id/file", "GET", false, true);
40+
if(isset($response["fileContent"])){
41+
return $response["fileContent"];
42+
} else {
43+
return false;
44+
}
45+
}
46+
47+
public function gitFetch(int $id){
48+
$response = $this->portainer->sendRequest([], "custom_templates/$id/git_fetch", "GET", false, true);
49+
if(isset($response["fileContent"])){
50+
return $response["fileContent"];
51+
} else {
52+
return false;
53+
}
54+
}
55+
56+
public function create(string $title, string $description, string $note, int $platform = 1, int $type = 2, string $file, string $logoUrl = null, string $variables = null){
57+
$response = $this->portainer->sendRequest([
58+
"title" => $title,
59+
"description" => $description,
60+
"note" => $note,
61+
"platform" => $platform,
62+
"type" => $type,
63+
"file" => $file,
64+
"logoUrl" => $logoUrl,
65+
"variables" => $variables
66+
], "custom_templates/create/file", "POST");
67+
if(isset($response["Id"])){
68+
return $response;
69+
} else {
70+
return false;
71+
}
72+
}
73+
74+
public function createRepository(array $data){
75+
$response = $this->portainer->sendRequest($data, "custom_templates/create/repository", "POST");
76+
if(isset($response["Id"])){
77+
return $response;
78+
} else {
79+
return false;
80+
}
81+
}
82+
83+
public function createFromString(array $data){
84+
$response = $this->portainer->sendRequest($data, "custom_templates/create/string", "POST");
85+
if(isset($response["Id"])){
86+
return $response;
87+
} else {
88+
return false;
89+
}
90+
}
91+
}

src/Endpoints/Docker/Docker.php

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
namespace Portainer\Endpoints;
3+
class Docker {
4+
private \Portainer\Portainer $portainer;
5+
6+
public function __construct(\Portainer\Portainer $portainer){
7+
$this->portainer = $portainer;
8+
}
9+
10+
/**
11+
* `gpus()` - Get the GPUs of a container
12+
* @param int $envId Environment ID
13+
* @param int $containerId Container ID
14+
* @return string|false Returns the GPUs or false
15+
*/
16+
public function gpus(int $envId, int $containerId){
17+
$response = $this->portainer->sendRequest([], "endpoints/$envId/docker/containers/$containerId/gpus", "GET", false, true);
18+
if(isset($response["gpus"])){
19+
return $response["gpus"];
20+
} else {
21+
return false;
22+
}
23+
}
24+
25+
/**
26+
* `images()` - Fetch images from the environment
27+
* @param int $envId Environment ID
28+
* @return array|bool Returns the images or false
29+
*/
30+
public function images(int $envId){
31+
$response = $this->portainer->sendRequest([], "endpoints/$envId/docker/images", "GET", false, true);
32+
if(isset($response[0])){
33+
return $response;
34+
} else {
35+
return false;
36+
}
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
namespace Portainer\Exceptions;
3+
class InvalidCredentialsException extends \Exception {
4+
public function __construct($message = "Invalid Credentials", $code = 0, \Exception $previous = null) {
5+
parent::__construct($message, $code, $previous);
6+
}
7+
}

src/Helper/Log.php

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
namespace Portainer\Helper;
3+
4+
class Log extends \Exception {
5+
6+
/**
7+
* Log constructor.
8+
* @param string $message The exception message
9+
* @param int $code The exception code
10+
* @param \Exception|null $previous A reference to the previous exception
11+
*/
12+
public function __construct($message, $code = 0, \Exception $previous = null){
13+
$trace = $this->getTraceAsString() ?? "N/A";
14+
$this->error_rep(message: $message, method: $trace);
15+
parent::__construct($message, $code, $previous);
16+
}
17+
18+
/**
19+
* @return string
20+
*/
21+
public function __toString(): string {
22+
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
23+
}
24+
25+
/**
26+
* `error_rep()` function is used to log the error message to the error log file.
27+
* @param string $message The error message to be logged.
28+
* @param string $method Name of either the method name that called the function or the request method.
29+
*/
30+
public static function error_rep($message, $method = null){
31+
$error_file = self::logrotate(); // file on your fs, e.g. /var/www/html/error.log
32+
$version = NULL;
33+
if($method == null){
34+
$method = @$_SERVER["REQUEST_METHOD"];
35+
}
36+
$uri = @$_SERVER["REQUEST_URI"];
37+
$host = @$_SERVER["HTTP_HOST"];
38+
$port = @$_SERVER["SERVER_PORT"];
39+
$script = @$_SERVER["SCRIPT_FILENAME"];
40+
$name = @$_SERVER["SERVER_NAME"] ?? "N/A";
41+
$addr = @$_SERVER["SERVER_ADDR"] ?? "N/A";
42+
$rhost = @$_SERVER["REMOTE_HOST"] ?? "N/A";
43+
$time = date("[d.m.Y | H:i:s]");
44+
error_log("{$time} \"{$message}\"\nURL: {$host}{$uri} \nVersion: {$version} Server IP:{$addr} - Server Name: {$name} - Request Method: '{$method}'\nRemote Addresse: {$addr} - Remote Name: '{$rhost}' - Remote Port: {$port}\nScript Name: '{$script}'\n=======================\n", 3, $error_file);
45+
46+
}
47+
48+
/**
49+
* `getSpecificLogFilePath()` function is used to get the specific log file path.
50+
* @param string|null $date The date to get the log file path for. Format: "Y-m-d".
51+
* @return string The specific log file path.
52+
*/
53+
private static function getSpecificLogFilePath($date = null){
54+
if($date == null){
55+
$date = date("Y-m-d");
56+
return __DIR__ . "/data/logs/log-{$date}.log";
57+
} else {
58+
preg_match("/^\d{4}-\d{2}-\d{2}$/m", $date, $match);
59+
if($match[0] == null){
60+
self::getSpecificLogFilePath();
61+
}
62+
Log::error_rep("Trying to get log file for date '$date'");
63+
return __DIR__ . "/data/logs/log-{$match[0]}.log";
64+
}
65+
}
66+
67+
/**
68+
* `logrotate()` function is used to rotate the log file.
69+
* @return string The path to the log file.
70+
*/
71+
private static function logrotate(){
72+
$logpath = __DIR__ . "/data/logs/";
73+
$date = date("Y-m-d");
74+
$lastrotate = @file_get_contents(__DIR__ . "/data/logs/logrotate-cache.txt");
75+
76+
if($date != $lastrotate){
77+
if(!file_exists($logpath . "log-{$date}.log")){
78+
$newlog = $logpath . "log-{$date}.log";
79+
file_put_contents($newlog, "");
80+
file_put_contents(__DIR__ . "/data/logs/logrotate-cache.txt", $date);
81+
}
82+
return __DIR__ . "/data/logs/log-{$date}.log";
83+
}
84+
return __DIR__ . "/data/logs/log-{$date}.log";
85+
}
86+
}

src/Helper/data/downloads/.gitkeep

Whitespace-only changes.

src/Helper/endpoints.json

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[
2+
"auth",
3+
"auth/logout",
4+
"auth/oauth/validate",
5+
6+
"backup",
7+
"restore",
8+
9+
"custom_templates",
10+
"custom_templates/create/file",
11+
"custom_templates/create/string",
12+
"custom_templates/create/repository"
13+
]

0 commit comments

Comments
 (0)