You've already forked Traefik-Redis-Api
FONDLED THE CODE
This commit is contained in:
96
README.md
96
README.md
@@ -1,28 +1,104 @@
|
|||||||
# Traefik Redis Provider API
|
# Traefik Redis Provider API
|
||||||
|
|
||||||
|
[Traefik](https://traefik.io/traefik/) is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy. This project provides
|
||||||
|
an api manager for the [Redis provider](https://doc.traefik.io/traefik/providers/redis/) for Traefik, allowing you to use Redis as a dynamic configuration backend.
|
||||||
|
|
||||||
|
## Running the Project
|
||||||
|
### Prerequisites
|
||||||
|
- Docker
|
||||||
|
- Traefik
|
||||||
|
- Redis
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
- `REDIS_HOST`: The URL of the Redis server. Default is `localhost`.
|
||||||
|
- `REDIS_PORT`: The port of the Redis server. Default is `6379`.
|
||||||
|
- `REDIS_DATABASE`: The database number to use. Default is `0`.
|
||||||
|
- `HTTP_PORT`: The port to run the HTTP server on. Default is `9501`.
|
||||||
|
```shell
|
||||||
|
docker run --rm -it -p 9501:9501 scr.siteworxpro.com/traefik-api:v1.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Get All Routes
|
||||||
|
```http request
|
||||||
|
GET http://localhost:9501/http/routes
|
||||||
|
Accept: application/json
|
||||||
|
```
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"route-1",
|
||||||
|
"route-2"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get a Route
|
||||||
|
```http request
|
||||||
|
GET http://localhost:9501/http/routes/route-1
|
||||||
|
Accept: application/json
|
||||||
|
```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "route-1",
|
||||||
|
"rule": "Host(`example.com`)",
|
||||||
|
"service": "service-1",
|
||||||
|
"middlewares": [
|
||||||
|
"middleware-1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Dev Environment
|
## Dev Environment
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- Docker
|
||||||
|
- Docker Compose
|
||||||
|
|
||||||
|
### Starting the Runtime
|
||||||
```shell
|
```shell
|
||||||
export PHP_IDE_CONFIG=serverName=localhost
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
### Start the server
|
||||||
|
```shell
|
||||||
|
docker exec -it traefik-redis-api-dev-runtime-1 rr serve
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can access the api at `http://localhost:9501/`
|
||||||
|
|
||||||
|
### Xdebug
|
||||||
|
|
||||||
|
xdebug needs to be built into the container before it will work
|
||||||
|
```shell
|
||||||
|
docker exec -it traefik-redis-api-dev-runtime-1 bin/xdebug.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install the dependencies
|
||||||
```shell
|
```shell
|
||||||
docker run --rm -v $(PWD):/app siteworxpro/composer install --ignore-platform-reqs
|
docker run --rm -v $(PWD):/app siteworxpro/composer install --ignore-platform-reqs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Running all tests
|
||||||
```shell
|
```shell
|
||||||
docker run --rm -v $(PWD):/app siteworxpro/composer run tests:all
|
docker run --rm -v $(PWD):/app siteworxpro/composer run tests:all
|
||||||
```
|
```
|
||||||
### migrations
|
|
||||||
create a new migration
|
|
||||||
```shell
|
## License
|
||||||
docker run --rm -v $(PWD):/app siteworxpro/migrate:v4.18.3 create -ext sql -dir /app/db/migrations -seq create_users_table
|
|
||||||
```
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
postgres://siteworxpro:password@localhost:5432/siteworxpro?sslmode=disable
|
Copyright (c)2025 Siteworx Professionals, LLC
|
||||||
```
|
|
||||||
|
|
||||||
```shell
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||||
docker run --rm -v $(PWD):/app siteworxpro/migrate:v4.18.3 -database "postgres://siteworxpro:password@localhost:5432/siteworxpro?sslmode=disable" -path /app/db/migrations up
|
documentation
|
||||||
|
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
|
||||||
|
the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
|
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
```
|
```
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#volumes:
|
volumes:
|
||||||
# pgdata: {}
|
redisdata: {}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
dev-runtime:
|
dev-runtime:
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "9501:9501"
|
||||||
volumes:
|
volumes:
|
||||||
- .:/app
|
- .:/app
|
||||||
build:
|
build:
|
||||||
@@ -14,24 +14,12 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
PHP_IDE_CONFIG: serverName=localhost
|
PHP_IDE_CONFIG: serverName=localhost
|
||||||
WORKERS: 1
|
WORKERS: 1
|
||||||
HTTP_PORT: 8080
|
|
||||||
DEBUG: 1
|
DEBUG: 1
|
||||||
REDIS_HOST: 192.168.1.30
|
REDIS_HOST: redis
|
||||||
|
|
||||||
# migrations:
|
redis:
|
||||||
# image: siteworxpro/migrate:v4.18.3
|
image: redis:latest
|
||||||
# restart: no
|
ports:
|
||||||
# volumes:
|
- "6379:6379"
|
||||||
# - .:/app
|
volumes:
|
||||||
# command: "-database 'postgres://${DB_DATABASE-siteworxpro}:${DB_PASSWORD-password}@${DB_HOST-postgres}:5432/siteworxpro?sslmode=disable' -path /app/db/migrations up"
|
- redisdata:/data
|
||||||
#
|
|
||||||
# postgres:
|
|
||||||
# image: postgres:latest
|
|
||||||
# environment:
|
|
||||||
# POSTGRES_USER: ${DB_USERNAME:-siteworxpro}
|
|
||||||
# POSTGRES_PASSWORD: ${DB_PASSWORD:-password}
|
|
||||||
# POSTGRES_DB: ${DB_DATABASE:-siteworxpro}
|
|
||||||
# ports:
|
|
||||||
# - "5432:5432"
|
|
||||||
# volumes:
|
|
||||||
# - pgdata:/var/lib/postgresql/data
|
|
||||||
@@ -4,12 +4,28 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Siteworxpro\App\Controllers;
|
namespace Siteworxpro\App\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use League\Route\Http\Exception\NotFoundException;
|
use League\Route\Http\Exception\NotFoundException;
|
||||||
use Nyholm\Psr7\ServerRequest;
|
use Nyholm\Psr7\ServerRequest;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Siteworxpro\App\Traefik\ProtocolEnum;
|
||||||
|
|
||||||
abstract class Controller implements ControllerInterface
|
abstract class Controller implements ControllerInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected function protocolEnumFromRequest(ServerRequest $request): ProtocolEnum
|
||||||
|
{
|
||||||
|
$protocol = $request->getAttribute('protocol');
|
||||||
|
|
||||||
|
try {
|
||||||
|
return ProtocolEnum::fromString($protocol);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
|
||||||
|
return ProtocolEnum::HTTP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServerRequest $request
|
* @param ServerRequest $request
|
||||||
* @return ResponseInterface
|
* @return ResponseInterface
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ class MiddlewaresController extends Controller
|
|||||||
if ($request->getAttribute('id') !== null) {
|
if ($request->getAttribute('id') !== null) {
|
||||||
$name = $request->getAttribute('id');
|
$name = $request->getAttribute('id');
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(RedisClient::getMiddleware($name));
|
return JsonResponseFactory::createJsonResponse(
|
||||||
|
RedisClient::getMiddleware($name, $this->protocolEnumFromRequest($request))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(RedisClient::getAllMiddlewares());
|
return JsonResponseFactory::createJsonResponse(
|
||||||
|
RedisClient::getAllMiddlewares($this->protocolEnumFromRequest($request))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +43,7 @@ class MiddlewaresController extends Controller
|
|||||||
return JsonResponseFactory::createJsonResponse(['error' => 'Middleware is invalid'], 400);
|
return JsonResponseFactory::createJsonResponse(['error' => 'Middleware is invalid'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
RedisClient::createOrReplace($name, $data, EntityEnum::MIDDLEWARE);
|
RedisClient::createOrReplace($name, $data, EntityEnum::MIDDLEWARE, $this->protocolEnumFromRequest($request));
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(['message' => 'Middleware added successfully']);
|
return JsonResponseFactory::createJsonResponse(['message' => 'Middleware added successfully']);
|
||||||
}
|
}
|
||||||
@@ -55,7 +59,7 @@ class MiddlewaresController extends Controller
|
|||||||
return JsonResponseFactory::createJsonResponse(['error' => 'Middleware is invalid'], 400);
|
return JsonResponseFactory::createJsonResponse(['error' => 'Middleware is invalid'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
RedisClient::deleteAllKeys($name, EntityEnum::MIDDLEWARE);
|
RedisClient::deleteAllKeys($name, EntityEnum::MIDDLEWARE , $this->protocolEnumFromRequest($request));
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(['message' => 'Middleware deleted successfully']);
|
return JsonResponseFactory::createJsonResponse(['message' => 'Middleware deleted successfully']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ class RoutesController extends Controller
|
|||||||
if ($request->getAttribute('id') !== null) {
|
if ($request->getAttribute('id') !== null) {
|
||||||
$name = $request->getAttribute('id');
|
$name = $request->getAttribute('id');
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(RedisClient::getRouter($name));
|
return JsonResponseFactory::createJsonResponse(
|
||||||
|
RedisClient::getRouter($name, $this->protocolEnumFromRequest($request))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(RedisClient::getAllRouters());
|
return JsonResponseFactory::createJsonResponse(
|
||||||
|
RedisClient::getAllRouters($this->protocolEnumFromRequest($request))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +47,12 @@ class RoutesController extends Controller
|
|||||||
return JsonResponseFactory::createJsonResponse(['error' => 'Rule is required'], 400);
|
return JsonResponseFactory::createJsonResponse(['error' => 'Rule is required'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
RedisClient::createOrReplace($name, $data, EntityEnum::ROUTER);
|
RedisClient::createOrReplace(
|
||||||
|
$name,
|
||||||
|
$data,
|
||||||
|
EntityEnum::ROUTER,
|
||||||
|
$this->protocolEnumFromRequest($request)
|
||||||
|
);
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(['message' => 'Router created successfully']);
|
return JsonResponseFactory::createJsonResponse(['message' => 'Router created successfully']);
|
||||||
}
|
}
|
||||||
@@ -55,7 +64,11 @@ class RoutesController extends Controller
|
|||||||
{
|
{
|
||||||
$name = $request->getAttribute('id');
|
$name = $request->getAttribute('id');
|
||||||
|
|
||||||
RedisClient::deleteAllKeys($name, EntityEnum::ROUTER);
|
RedisClient::deleteAllKeys(
|
||||||
|
$name,
|
||||||
|
EntityEnum::ROUTER,
|
||||||
|
$this->protocolEnumFromRequest($request)
|
||||||
|
);
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(['message' => 'Router deleted successfully']);
|
return JsonResponseFactory::createJsonResponse(['message' => 'Router deleted successfully']);
|
||||||
}
|
}
|
||||||
@@ -70,7 +83,7 @@ class RoutesController extends Controller
|
|||||||
$data = $request->getParsedBody();
|
$data = $request->getParsedBody();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RedisClient::patchEntity($name, $data, EntityEnum::ROUTER);
|
RedisClient::patchEntity($name, $data, EntityEnum::ROUTER, $this->protocolEnumFromRequest($request));
|
||||||
} catch (\InvalidArgumentException) {
|
} catch (\InvalidArgumentException) {
|
||||||
return JsonResponseFactory::createJsonResponse(['error' => 'Router not found'], 404);
|
return JsonResponseFactory::createJsonResponse(['error' => 'Router not found'], 404);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ class ServicesController extends Controller
|
|||||||
if ($request->getAttribute('id') !== null) {
|
if ($request->getAttribute('id') !== null) {
|
||||||
$name = $request->getAttribute('id');
|
$name = $request->getAttribute('id');
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(RedisClient::getService($name));
|
return JsonResponseFactory::createJsonResponse(
|
||||||
|
RedisClient::getService($name, $this->protocolEnumFromRequest($request))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(RedisClient::getAllServices());
|
return JsonResponseFactory::createJsonResponse(
|
||||||
|
RedisClient::getAllServices($this->protocolEnumFromRequest($request))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +43,7 @@ class ServicesController extends Controller
|
|||||||
return JsonResponseFactory::createJsonResponse(['error' => 'loadbalancer is required'], 400);
|
return JsonResponseFactory::createJsonResponse(['error' => 'loadbalancer is required'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
RedisClient::createOrReplace($name, $data, EntityEnum::SERVICE);
|
RedisClient::createOrReplace($name, $data, EntityEnum::SERVICE, $this->protocolEnumFromRequest($request));
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(['message' => 'Service updated successfully']);
|
return JsonResponseFactory::createJsonResponse(['message' => 'Service updated successfully']);
|
||||||
}
|
}
|
||||||
@@ -55,7 +59,7 @@ class ServicesController extends Controller
|
|||||||
return JsonResponseFactory::createJsonResponse(['error' => 'Service name is required'], 400);
|
return JsonResponseFactory::createJsonResponse(['error' => 'Service name is required'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
RedisClient::deleteAllKeys($name, EntityEnum::SERVICE);
|
RedisClient::deleteAllKeys($name, EntityEnum::SERVICE, $this->protocolEnumFromRequest($request));
|
||||||
|
|
||||||
return JsonResponseFactory::createJsonResponse(['message' => 'Service deleted successfully']);
|
return JsonResponseFactory::createJsonResponse(['message' => 'Service deleted successfully']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,10 @@ class Server
|
|||||||
*/
|
*/
|
||||||
protected function registerRoutes(): void
|
protected function registerRoutes(): void
|
||||||
{
|
{
|
||||||
$this->router->group('/http/routes', function (RouteGroup $router) {
|
$this->router->addPatternMatcher('protocolEnums', 'http|tcp|udp');
|
||||||
|
$this->router->addPatternMatcher('protocolEnumsMiddleware', 'http|tcp');
|
||||||
|
|
||||||
|
$this->router->group('/{protocol:protocolEnums}/routes', function (RouteGroup $router) {
|
||||||
$router->get('/', RoutesController::class . '::get');
|
$router->get('/', RoutesController::class . '::get');
|
||||||
$router->get('/{id}', RoutesController::class . '::get');
|
$router->get('/{id}', RoutesController::class . '::get');
|
||||||
$router->post('/{id}', RoutesController::class . '::post');
|
$router->post('/{id}', RoutesController::class . '::post');
|
||||||
@@ -128,14 +131,14 @@ class Server
|
|||||||
$router->delete('/{id}', RoutesController::class . '::delete');
|
$router->delete('/{id}', RoutesController::class . '::delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->router->group('/http/services', function (RouteGroup $router) {
|
$this->router->group('/{protocol:protocolEnums}/services', function (RouteGroup $router) {
|
||||||
$router->get('/', ServicesController::class . '::get');
|
$router->get('/', ServicesController::class . '::get');
|
||||||
$router->get('/{id}', ServicesController::class . '::get');
|
$router->get('/{id}', ServicesController::class . '::get');
|
||||||
$router->post('/{id}', ServicesController::class . '::post');
|
$router->post('/{id}', ServicesController::class . '::post');
|
||||||
$router->delete('/{id}', ServicesController::class . '::delete');
|
$router->delete('/{id}', ServicesController::class . '::delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->router->group('/http/middlewares', function (RouteGroup $router) {
|
$this->router->group('/{protocol:protocolEnumsMiddleware}/middlewares', function (RouteGroup $router) {
|
||||||
$router->get('/', MiddlewaresController::class . '::get');
|
$router->get('/', MiddlewaresController::class . '::get');
|
||||||
$router->get('/{id}', MiddlewaresController::class . '::get');
|
$router->get('/{id}', MiddlewaresController::class . '::get');
|
||||||
$router->post('/{id}', MiddlewaresController::class . '::post');
|
$router->post('/{id}', MiddlewaresController::class . '::post');
|
||||||
|
|||||||
@@ -18,4 +18,14 @@ enum ProtocolEnum
|
|||||||
self::UDP => 'udp',
|
self::UDP => 'udp',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromString(string $value): self
|
||||||
|
{
|
||||||
|
return match ($value) {
|
||||||
|
'http' => self::HTTP,
|
||||||
|
'tcp' => self::TCP,
|
||||||
|
'udp' => self::UDP,
|
||||||
|
default => throw new \InvalidArgumentException("Invalid protocol: $value"),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user