feat: complete MVP epics E7-E10 (provisioning, console proxy, audit, frontend)
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type SQLRepository struct {
|
||||
@@ -171,5 +172,140 @@ func (r nullableVMRecord) vm() VM {
|
||||
UpdatedAt: r.UpdatedAt.Time,
|
||||
ProjectName: r.ProjectName,
|
||||
MembershipRole: r.MembershipRole,
|
||||
}
|
||||
}
|
||||
|
||||
type ProjectInfo struct {
|
||||
TenantID string
|
||||
Name string
|
||||
Role string
|
||||
}
|
||||
|
||||
type QuotaInfo struct {
|
||||
UsedVMs int
|
||||
UsedVCPU int
|
||||
UsedRAMMB int
|
||||
UsedDiskGB int
|
||||
MaxVMs int
|
||||
MaxVCPU int
|
||||
MaxRAMMB int
|
||||
MaxDiskGB int
|
||||
}
|
||||
|
||||
func (r SQLRepository) GetProjectInfo(ctx context.Context, profileID string, projectID string) (ProjectInfo, bool, error) {
|
||||
var info ProjectInfo
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
select
|
||||
p.tenant_id::text,
|
||||
p.name,
|
||||
m.role::text
|
||||
from public.projects p
|
||||
join public.memberships m
|
||||
on m.tenant_id = p.tenant_id
|
||||
and m.profile_id = $1
|
||||
where p.id = $2
|
||||
`, profileID, projectID).Scan(&info.TenantID, &info.Name, &info.Role)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ProjectInfo{}, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return ProjectInfo{}, false, err
|
||||
}
|
||||
|
||||
return info, true, nil
|
||||
}
|
||||
|
||||
func (r SQLRepository) CheckQuota(ctx context.Context, projectID string) (QuotaInfo, error) {
|
||||
var q QuotaInfo
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
select
|
||||
coalesce(sum(case when v.status <> 'failed' and v.status <> 'deleting' and v.status <> 'deleted' then 1 else 0 end), 0) as used_vms,
|
||||
coalesce(sum(case when v.status <> 'failed' and v.status <> 'deleting' and v.status <> 'deleted' then v.vcpu else 0 end), 0) as used_vcpu,
|
||||
coalesce(sum(case when v.status <> 'failed' and v.status <> 'deleting' and v.status <> 'deleted' then v.ram_mb else 0 end), 0) as used_ram_mb,
|
||||
coalesce(sum(case when v.status <> 'failed' and v.status <> 'deleting' and v.status <> 'deleted' then v.disk_gb else 0 end), 0) as used_disk_gb,
|
||||
coalesce(pq.max_vms, 10),
|
||||
coalesce(pq.max_vcpu, 8),
|
||||
coalesce(pq.max_ram_mb, 16384),
|
||||
coalesce(pq.max_disk_gb, 200)
|
||||
from public.projects p
|
||||
left join public.vms v on v.project_id = p.id
|
||||
left join public.project_quotas pq on pq.project_id = p.id
|
||||
where p.id = $1
|
||||
group by pq.max_vms, pq.max_vcpu, pq.max_ram_mb, pq.max_disk_gb
|
||||
`, projectID).Scan(&q.UsedVMs, &q.UsedVCPU, &q.UsedRAMMB, &q.UsedDiskGB, &q.MaxVMs, &q.MaxVCPU, &q.MaxRAMMB, &q.MaxDiskGB)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
q.MaxVMs = 10
|
||||
q.MaxVCPU = 8
|
||||
q.MaxRAMMB = 16384
|
||||
q.MaxDiskGB = 200
|
||||
return q, nil
|
||||
}
|
||||
if err != nil {
|
||||
return QuotaInfo{}, err
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (r SQLRepository) ReserveNextVMID(ctx context.Context, clusterID string) (int, error) {
|
||||
var vmid int
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
select public.reserve_next_vmid($1::uuid)
|
||||
`, clusterID).Scan(&vmid)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reserve vmid: %w", err)
|
||||
}
|
||||
|
||||
return vmid, nil
|
||||
}
|
||||
|
||||
func (r SQLRepository) InsertVM(ctx context.Context, vm InsertVMRecord) (VM, error) {
|
||||
var result VM
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
insert into public.vms (project_id, cluster_id, proxmox_vmid, node, name, status, vcpu, ram_mb, disk_gb)
|
||||
values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
returning
|
||||
id::text,
|
||||
project_id::text,
|
||||
cluster_id::text,
|
||||
proxmox_vmid,
|
||||
node,
|
||||
name,
|
||||
status::text,
|
||||
vcpu,
|
||||
ram_mb,
|
||||
disk_gb,
|
||||
created_at,
|
||||
updated_at
|
||||
`, vm.ProjectID, vm.ClusterID, vm.ProxmoxVMID, vm.Node, vm.Name, vm.Status, vm.VCPU, vm.RAMMB, vm.DiskGB).Scan(
|
||||
&result.ID,
|
||||
&result.ProjectID,
|
||||
&result.ClusterID,
|
||||
&result.ProxmoxVMID,
|
||||
&result.Node,
|
||||
&result.Name,
|
||||
&result.Status,
|
||||
&result.VCPU,
|
||||
&result.RAMMB,
|
||||
&result.DiskGB,
|
||||
&result.CreatedAt,
|
||||
&result.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return VM{}, fmt.Errorf("insert vm: %w", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type InsertVMRecord struct {
|
||||
ProjectID string
|
||||
ClusterID string
|
||||
ProxmoxVMID int
|
||||
Node string
|
||||
Name string
|
||||
Status string
|
||||
VCPU int
|
||||
RAMMB int
|
||||
DiskGB int
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user