mirror of
https://github.com/ConvoyPanel/panel.git
synced 2026-06-05 16:19:22 +08:00
add unfinished backend for ip pool support
This commit is contained in:
10
app/Http/Controllers/Admin/AddressController.php
Normal file
10
app/Http/Controllers/Admin/AddressController.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Convoy\Http\Controllers\Admin;
|
||||
|
||||
use Convoy\Http\Controllers\ApplicationApiController;
|
||||
|
||||
class AddressController extends ApplicationApiController
|
||||
{
|
||||
//
|
||||
}
|
||||
75
app/Http/Controllers/Admin/AddressPoolController.php
Normal file
75
app/Http/Controllers/Admin/AddressPoolController.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Convoy\Http\Controllers\Admin;
|
||||
|
||||
use Convoy\Http\Controllers\ApplicationApiController;
|
||||
use Convoy\Http\Requests\Admin\AddressPools\StoreAddressPoolRequest;
|
||||
use Convoy\Http\Requests\Admin\AddressPools\UpdateAddressPoolRequest;
|
||||
use Convoy\Models\AddressPool;
|
||||
use Convoy\Models\Filters\FiltersAddressPool;
|
||||
use Convoy\Models\Filters\FiltersNode;
|
||||
use Convoy\Transformers\Admin\AddressPoolTransformer;
|
||||
use Convoy\Transformers\Admin\NodeTransformer;
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\QueryBuilder\AllowedFilter;
|
||||
use Spatie\QueryBuilder\QueryBuilder;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
class AddressPoolController extends ApplicationApiController
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$addressPools = QueryBuilder::for(AddressPool::query())
|
||||
->withCount(['addresses', 'nodes'])
|
||||
->allowedFilters(['name', AllowedFilter::custom('*', new FiltersAddressPool)])
|
||||
->paginate(min($request->query('per_page', 50), 100))->appends($request->query());
|
||||
|
||||
return fractal($addressPools, new AddressPoolTransformer)->respond();
|
||||
}
|
||||
|
||||
public function show(AddressPool $addressPool)
|
||||
{
|
||||
$addressPool->loadCount(['addresses', 'nodes']);
|
||||
|
||||
return fractal($addressPool, new AddressPoolTransformer)->respond();
|
||||
}
|
||||
|
||||
public function getNodesAllocatedTo(Request $request, AddressPool $addressPool)
|
||||
{
|
||||
$nodes = QueryBuilder::for($addressPool->nodes())
|
||||
->withCount('servers')
|
||||
->allowedFilters(['name', 'fqdn', AllowedFilter::exact('location_id'), AllowedFilter::custom('*', new FiltersNode)])
|
||||
->paginate(min($request->query('per_page', 50), 100))->appends($request->query());
|
||||
|
||||
return fractal($nodes, new NodeTransformer())->respond();
|
||||
}
|
||||
|
||||
public function store(StoreAddressPoolRequest $request)
|
||||
{
|
||||
$pool = AddressPool::create($request->validated());
|
||||
$pool->loadCount(['addresses', 'nodes']);
|
||||
|
||||
return fractal($pool, new AddressPoolTransformer)->respond();
|
||||
}
|
||||
|
||||
public function update(UpdateAddressPoolRequest $request, AddressPool $addressPool)
|
||||
{
|
||||
$addressPool->update($request->validated());
|
||||
$addressPool->loadCount(['addresses', 'nodes']);
|
||||
|
||||
return fractal($addressPool, new AddressPoolTransformer)->respond();
|
||||
}
|
||||
|
||||
public function destroy(AddressPool $addressPool)
|
||||
{
|
||||
$addressPool->loadCount('nodes');
|
||||
|
||||
if ($addressPool->nodes_count > 0) {
|
||||
throw new AccessDeniedHttpException('This address pool cannot be deleted while still allocated to nodes.');
|
||||
}
|
||||
|
||||
$addressPool->delete();
|
||||
|
||||
return $this->returnNoContent();
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ class NodeController extends ApplicationApiController
|
||||
public function index(Request $request)
|
||||
{
|
||||
$nodes = QueryBuilder::for(Node::query())
|
||||
->with('servers')
|
||||
->withCount(['servers'])
|
||||
->allowedFilters(['name', 'fqdn', AllowedFilter::exact('location_id'), AllowedFilter::custom('*', new FiltersNode)])
|
||||
->paginate(min($request->query('per_page', 50), 100))->appends($request->query());
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Convoy\Http\Requests\Admin\AddressPools;
|
||||
|
||||
use Convoy\Models\AddressPool;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreAddressPoolRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return AddressPool::getRules();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Convoy\Http\Requests\Admin\AddressPools;
|
||||
|
||||
use Convoy\Http\Requests\FormRequest;
|
||||
use Convoy\Models\AddressPool;
|
||||
|
||||
class UpdateAddressPoolRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
$addressPool = $this->parameter('address_pool', AddressPool::class);
|
||||
|
||||
return AddressPool::getRulesForUpdate($addressPool);
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,6 @@ use Illuminate\Validation\Validator;
|
||||
|
||||
class UpdateGroupOrderRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Convoy\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Address extends Model
|
||||
{
|
||||
@@ -22,7 +23,7 @@ class Address extends Model
|
||||
'mac_address' => ['mac_address', 'nullable'],
|
||||
];
|
||||
|
||||
public function server()
|
||||
public function server(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Server::class);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,41 @@
|
||||
|
||||
namespace Convoy\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class AddressPool extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
/**
|
||||
* Fields that aren't mass assignable
|
||||
*/
|
||||
protected $guarded = ['id', 'updated_at', 'created_at'];
|
||||
|
||||
public static $validationRules = [
|
||||
'name' => 'required|string|max:191',
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets the nodes that an address pool is allocated to.
|
||||
*/
|
||||
public function nodes(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Node::class, 'address_pool_to_node', 'address_pool_id', 'node_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the addresses that are associated with an address pool.
|
||||
*/
|
||||
public function addresses(): HasMany
|
||||
{
|
||||
return $this->hasMany(Address::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* The column Laravel should look at for route model binding.
|
||||
*/
|
||||
public function getRouteKeyName(): string
|
||||
{
|
||||
return 'id';
|
||||
}
|
||||
}
|
||||
|
||||
35
app/Models/AddressPoolToNode.php
Normal file
35
app/Models/AddressPoolToNode.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Convoy\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
|
||||
/**
|
||||
* This is a pivot table for linking address pools to nodes in a many-to-many relation.
|
||||
* An address pool can be allocated to multiple nodes. Similarly, multiple nodes can
|
||||
* be allocated to a single address pool.
|
||||
*/
|
||||
class AddressPoolToNode extends Model
|
||||
{
|
||||
/**
|
||||
* The actual name of the table Laravel ORM should query.
|
||||
*/
|
||||
protected $table = 'address_pool_to_node';
|
||||
|
||||
public function addressPool(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(AddressPool::class);
|
||||
}
|
||||
|
||||
public function node(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Node::class);
|
||||
}
|
||||
|
||||
public function addresses(): HasManyThrough
|
||||
{
|
||||
return $this->hasManyThrough(Address::class, AddressPool::class);
|
||||
}
|
||||
}
|
||||
15
app/Models/Filters/FiltersAddressPool.php
Normal file
15
app/Models/Filters/FiltersAddressPool.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Convoy\Models\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Spatie\QueryBuilder\Filters\Filter;
|
||||
|
||||
class FiltersAddressPool implements Filter
|
||||
{
|
||||
public function __invoke(Builder $query, $value, string $property)
|
||||
{
|
||||
$query->where('id', $value)
|
||||
->orWhereRaw('LOWER(name) LIKE ?', ["%$value%"]);
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,30 @@ use Convoy\Casts\MebibytesToAndFromBytes;
|
||||
use Convoy\Casts\NullableEncrypter;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
|
||||
class Node extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The constants for generating temporary Coterm (a noVNC reverse proxy) session tokens
|
||||
*/
|
||||
public const COTERM_TOKEN_ID_LENGTH = 16;
|
||||
public const COTERM_TOKEN_LENGTH = 64;
|
||||
|
||||
/**
|
||||
* The attributes excluded from the model's JSON form.
|
||||
*/
|
||||
protected $hidden = [
|
||||
'token_id', 'secret', 'coterm_token_id', 'coterm_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Cast values to correct type.
|
||||
*/
|
||||
protected $casts = [
|
||||
'memory' => MebibytesToAndFromBytes::class,
|
||||
'disk' => MebibytesToAndFromBytes::class,
|
||||
@@ -23,6 +39,9 @@ class Node extends Model
|
||||
'coterm_token' => NullableEncrypter::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Fields that aren't mass assignable
|
||||
*/
|
||||
protected $guarded = ['id', 'created_at', 'updated_at'];
|
||||
|
||||
public static $validationRules = [
|
||||
@@ -49,34 +68,62 @@ class Node extends Model
|
||||
'coterm_token' => 'required_if:coterm_enabled,1',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'token_id', 'secret', 'coterm_token_id', 'coterm_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the connection address to use when making calls to this node.
|
||||
* Get the connection address to use when making calls to this node's assigned Coterm endpoint.
|
||||
*/
|
||||
public function getCotermConnectionAddress(): string
|
||||
{
|
||||
return sprintf('%s://%s:%s', $this->coterm_tls_enabled ? 'https' : 'http', $this->coterm_fqdn, $this->coterm_port);
|
||||
}
|
||||
|
||||
public function servers()
|
||||
/**
|
||||
* Gets the servers associated with a node.
|
||||
*/
|
||||
public function servers(): HasMany
|
||||
{
|
||||
return $this->hasMany(Server::class);
|
||||
}
|
||||
|
||||
public function addresses()
|
||||
/**
|
||||
* Gets the address pools allocated to a node.
|
||||
*/
|
||||
public function addressPools(): BelongsToMany
|
||||
{
|
||||
return $this->hasMany(Address::class);
|
||||
return $this->belongsToMany(
|
||||
AddressPool::class,
|
||||
'address_pool_to_node',
|
||||
'node_id',
|
||||
'address_pool_id'
|
||||
);
|
||||
}
|
||||
|
||||
public function templateGroups()
|
||||
/**
|
||||
* Gets all the addresses associated with a node from the address pool(s) allocated to a node.
|
||||
*/
|
||||
public function addresses(): HasManyThrough
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Address::class,
|
||||
AddressPoolToNode::class,
|
||||
'node_id',
|
||||
'address_pool_id',
|
||||
'id',
|
||||
'address_pool_id'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template groups associated with a node. This is not the same as TEMPLATES.
|
||||
*/
|
||||
public function templateGroups(): HasMany
|
||||
{
|
||||
return $this->hasMany(TemplateGroup::class);
|
||||
}
|
||||
|
||||
public function isos()
|
||||
/**
|
||||
* Gets the ISOs downloaded on a node.
|
||||
*/
|
||||
public function isos(): HasMany
|
||||
{
|
||||
return $this->hasMany(ISO::class);
|
||||
}
|
||||
@@ -89,18 +136,27 @@ class Node extends Model
|
||||
return $this->belongsTo(Location::class);
|
||||
}
|
||||
|
||||
public function getRouteKeyName(): string
|
||||
{
|
||||
return 'id';
|
||||
}
|
||||
|
||||
public function getDiskAllocatedAttribute()
|
||||
/**
|
||||
* Gets the total disk used from adding up all the associated servers' disk sizes.
|
||||
*/
|
||||
public function getDiskAllocatedAttribute(): int
|
||||
{
|
||||
return $this->servers->sum('disk');
|
||||
}
|
||||
|
||||
public function getMemoryAllocatedAttribute()
|
||||
/**
|
||||
* Gets the total memory used from adding up all the associated servers' allocated memory.
|
||||
*/
|
||||
public function getMemoryAllocatedAttribute(): int
|
||||
{
|
||||
return $this->servers->sum('memory');
|
||||
}
|
||||
|
||||
/**
|
||||
* The column Laravel should look at for route model binding.
|
||||
*/
|
||||
public function getRouteKeyName(): string
|
||||
{
|
||||
return 'id';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ class PersonalAccessToken extends SanctumPersonalAccessToken
|
||||
{
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'type',
|
||||
|
||||
@@ -5,13 +5,12 @@ namespace Convoy\Services\Servers;
|
||||
use Convoy\Data\Server\Eloquent\ServerEloquentData;
|
||||
use Convoy\Data\Server\Proxmox\ServerProxmoxData;
|
||||
use Convoy\Models\Server;
|
||||
use Convoy\Repositories\Proxmox\Server\ProxmoxCloudinitRepository;
|
||||
use Convoy\Repositories\Proxmox\Server\ProxmoxConfigRepository;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class ServerDetailService
|
||||
{
|
||||
public function __construct(private NetworkService $networkService, private ProxmoxConfigRepository $allocationRepository, private ProxmoxCloudinitRepository $cloudinitRepository, private AllocationService $allocationService, private CloudinitService $cloudinitService)
|
||||
public function __construct(private NetworkService $networkService, private ProxmoxConfigRepository $allocationRepository, private AllocationService $allocationService,)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
19
app/Transformers/Admin/AddressPoolTransformer.php
Normal file
19
app/Transformers/Admin/AddressPoolTransformer.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Convoy\Transformers\Admin;
|
||||
|
||||
use Convoy\Models\AddressPool;
|
||||
use League\Fractal\TransformerAbstract;
|
||||
|
||||
class AddressPoolTransformer extends TransformerAbstract
|
||||
{
|
||||
public function transform(AddressPool $pool): array
|
||||
{
|
||||
return [
|
||||
'id' => $pool->id,
|
||||
'name' => $pool->name,
|
||||
'nodes_count' => (int) $pool->nodes_count,
|
||||
'addresses_count' => (int) $pool->addresses_count,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -95,4 +95,5 @@ return [
|
||||
'iso' => 'ISO',
|
||||
'iso_one' => 'ISO',
|
||||
'iso_other' => 'ISOs',
|
||||
'ipam' => 'IPAM',
|
||||
];
|
||||
|
||||
683
package-lock.json
generated
683
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,7 @@
|
||||
"@mantine/notifications": "^5.9.4",
|
||||
"@mantine/nprogress": "^5.9.4",
|
||||
"@tailwindcss/forms": "^0.5.2",
|
||||
"@tanstack/react-query": "^4.0.5",
|
||||
"@tanstack/react-table": "^8.7.0",
|
||||
"@vitejs/plugin-react": "^1.3.2",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"axios": "^0.25.0",
|
||||
"chart.js": "^3.8.0",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
const IpamContainer = () => {}
|
||||
|
||||
export default IpamContainer
|
||||
@@ -7,7 +7,7 @@ interface Props {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const Drawer = forwardRef<HTMLDivElement, Props>(({ open, onClose, children }: Props, ref) => {
|
||||
const Drawer = forwardRef<HTMLDivElement, Props>(({ open, onClose, children }, ref) => {
|
||||
const focusTrapRef = useRef(null)
|
||||
|
||||
return (
|
||||
|
||||
@@ -71,6 +71,10 @@ const AdminDashboardRouter = () => {
|
||||
name: tStrings('server_other'),
|
||||
path: '/admin/servers',
|
||||
},
|
||||
{
|
||||
name: tStrings('ipam'),
|
||||
path: '/admin/ipam',
|
||||
},
|
||||
{
|
||||
name: tStrings('user_other'),
|
||||
path: '/admin/users',
|
||||
|
||||
@@ -48,6 +48,10 @@ Route::prefix('/servers/{server}')->middleware(ValidateServerStatusMiddleware::c
|
||||
});
|
||||
});
|
||||
|
||||
Route::resource('address-pools', Admin\AddressPoolController::class)
|
||||
->only(['index', 'show', 'store', 'update', 'destroy']);
|
||||
Route::get('/address-pools/{address_pool}/nodes', [Admin\AddressPoolController::class, 'getNodesAllocatedTo']);
|
||||
|
||||
Route::resource('users', Admin\UserController::class)
|
||||
->only(['index', 'show', 'store', 'update', 'destroy']);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user