mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25a8443548 |
No files matched your search
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -210,7 +211,7 @@ func basicAuthUsernames(encoded string) []string {
|
|||||||
// serviceWriteAccess mirrors the service update handler's access check.
|
// serviceWriteAccess mirrors the service update handler's access check.
|
||||||
func serviceWriteAccess(c *gin.Context, db *database.DB, serviceID uuid.UUID) bool {
|
func serviceWriteAccess(c *gin.Context, db *database.DB, serviceID uuid.UUID) bool {
|
||||||
userID, _ := c.Get("user_id")
|
userID, _ := c.Get("user_id")
|
||||||
uid, _ := userID.(uuid.UUID)
|
uid, _ := uuid.Parse(fmt.Sprint(userID))
|
||||||
ok, err := sqlcdb.New(db.DB).ServiceWriteAccess(context.Background(), sqlcdb.ServiceWriteAccessParams{
|
ok, err := sqlcdb.New(db.DB).ServiceWriteAccess(context.Background(), sqlcdb.ServiceWriteAccessParams{
|
||||||
ID: serviceID,
|
ID: serviceID,
|
||||||
OwnerID: uid,
|
OwnerID: uid,
|
||||||
|
|||||||
@@ -143,3 +143,83 @@ func TestServiceDomainsLiveInvariants(t *testing.T) {
|
|||||||
t.Fatalf("legacy after delete = %q, want %q", legacy, d1.Domain)
|
t.Fatalf("legacy after delete = %q, want %q", legacy, d1.Domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Live clone test: cloneServiceRow must copy config, domains, and variables
|
||||||
|
// verbatim, start stopped, and land in the target project/environment.
|
||||||
|
func TestCloneServiceRowLive(t *testing.T) {
|
||||||
|
dsn := testDSNString(t)
|
||||||
|
db, err := database.NewConnection(dsn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("connect: %v", err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
ctx := context.Background()
|
||||||
|
q := sqlcdb.New(db.DB)
|
||||||
|
|
||||||
|
userID := uuid.New()
|
||||||
|
projectID := uuid.New()
|
||||||
|
envID := uuid.New()
|
||||||
|
serviceID := uuid.New()
|
||||||
|
suffix := strings.ReplaceAll(serviceID.String()[:8], "-", "")
|
||||||
|
must := func(err error) {
|
||||||
|
t.Helper()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("setup: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = db.Exec(`INSERT INTO users (id, email, password_hash, name) VALUES ($1, $2, 'x', 'test')`,
|
||||||
|
userID, "clone-"+suffix+"@test.local")
|
||||||
|
must(err)
|
||||||
|
_, err = db.Exec(`INSERT INTO projects (id, name, owner_id, is_approved) VALUES ($1, $2, $3, true)`,
|
||||||
|
projectID, "clone-"+suffix, userID)
|
||||||
|
must(err)
|
||||||
|
_, err = db.Exec(`INSERT INTO environments (id, name, project_id) VALUES ($1, 'production', $2)`,
|
||||||
|
envID, projectID)
|
||||||
|
must(err)
|
||||||
|
_, err = db.Exec(`INSERT INTO services (id, name, project_id, environment_id, service_type, source_type,
|
||||||
|
image_name, port, volumes, traefik_labels, maintenance_mode)
|
||||||
|
VALUES ($1, $2, $3, $4, 'web', 'image', 'traefik/whoami:latest', 80,
|
||||||
|
'[{"mount":"/data"}]'::jsonb,
|
||||||
|
'{"middlewares.rl.ratelimit.average":"100"}'::jsonb, true)`,
|
||||||
|
serviceID, "clonesrc-"+suffix, projectID, envID)
|
||||||
|
must(err)
|
||||||
|
defer func() { _, _ = db.Exec(`DELETE FROM users WHERE id = $1`, userID) }()
|
||||||
|
|
||||||
|
if _, err := q.CreateServiceDomain(ctx, sqlcdb.CreateServiceDomainParams{
|
||||||
|
ServiceID: serviceID, Domain: "src-" + suffix + ".example.com", IsDefault: true}); err != nil {
|
||||||
|
t.Fatalf("seed domain: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`INSERT INTO environment_variables (id, service_id, key, value, is_secret)
|
||||||
|
VALUES ($1, $2, 'FOO', 'bar', false)`, uuid.New(), serviceID); err != nil {
|
||||||
|
t.Fatalf("seed var: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cloneID, err := cloneServiceRow(db, serviceID, projectID, "clone-"+suffix, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("clone: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var status, imageName, env string
|
||||||
|
var maintenance bool
|
||||||
|
var volumes, labels []byte
|
||||||
|
if err := db.QueryRow(`SELECT status, image_name, COALESCE(environment,''), maintenance_mode,
|
||||||
|
volumes, traefik_labels FROM services WHERE id = $1`, cloneID).
|
||||||
|
Scan(&status, &imageName, &env, &maintenance, &volumes, &labels); err != nil {
|
||||||
|
t.Fatalf("read clone: %v", err)
|
||||||
|
}
|
||||||
|
if status != "stopped" || imageName != "traefik/whoami:latest" || env != "production" {
|
||||||
|
t.Fatalf("clone mismatch: %v %v %v", status, imageName, env)
|
||||||
|
}
|
||||||
|
if !maintenance || string(volumes) == "[]" || string(labels) == "{}" {
|
||||||
|
t.Fatalf("clone dropped config: maint=%v vol=%s labels=%s", maintenance, volumes, labels)
|
||||||
|
}
|
||||||
|
doms := loadServiceDomains(db, cloneID)
|
||||||
|
if len(doms) != 1 || doms[0].Domain != "src-"+suffix+".example.com" || !doms[0].IsDefault {
|
||||||
|
t.Fatalf("domains not cloned: %+v", doms)
|
||||||
|
}
|
||||||
|
var varVal string
|
||||||
|
if err := db.QueryRow(`SELECT value FROM environment_variables WHERE service_id = $1 AND key = 'FOO'`,
|
||||||
|
cloneID).Scan(&varVal); err != nil || varVal != "bar" {
|
||||||
|
t.Fatalf("vars not cloned: %v %q", err, varVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"containr/internal/database"
|
"containr/internal/database"
|
||||||
|
"containr/internal/database/sqlcdb"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -53,11 +56,8 @@ func handleCloneService(c *gin.Context) {
|
|||||||
if name == "" {
|
if name == "" {
|
||||||
name = source.Name + "-copy"
|
name = source.Name + "-copy"
|
||||||
}
|
}
|
||||||
var count int
|
count, _ := sqlcdb.New(db.(*database.DB).DB).CountServicesByName(
|
||||||
_ = db.(*database.DB).QueryRow(
|
c.Request.Context(), sqlcdb.CountServicesByNameParams{ProjectID: targetProjectID, Name: name})
|
||||||
`SELECT COUNT(*) FROM services WHERE project_id = $1 AND name = $2`,
|
|
||||||
targetProjectID, name,
|
|
||||||
).Scan(&count)
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
c.JSON(http.StatusConflict, gin.H{"error": "Service name already exists in target project", "code": "CONFLICT"})
|
c.JSON(http.StatusConflict, gin.H{"error": "Service name already exists in target project", "code": "CONFLICT"})
|
||||||
return
|
return
|
||||||
@@ -84,8 +84,11 @@ func handleCloneService(c *gin.Context) {
|
|||||||
// inherits the source's. Used by the clone endpoint and preview
|
// inherits the source's. Used by the clone endpoint and preview
|
||||||
// environments, which additionally override git_branch and domains.
|
// environments, which additionally override git_branch and domains.
|
||||||
func cloneServiceRow(db *database.DB, sourceID uuid.UUID, targetProjectID uuid.UUID, name, environment string) (uuid.UUID, error) {
|
func cloneServiceRow(db *database.DB, sourceID uuid.UUID, targetProjectID uuid.UUID, name, environment string) (uuid.UUID, error) {
|
||||||
var sourceEnv string
|
ctx := context.Background()
|
||||||
if err := db.QueryRow(`SELECT COALESCE(environment, '') FROM services WHERE id = $1`, sourceID).Scan(&sourceEnv); err != nil {
|
q := sqlcdb.New(db.DB)
|
||||||
|
|
||||||
|
sourceEnv, err := q.GetServiceEnvironment(ctx, sourceID)
|
||||||
|
if err != nil {
|
||||||
return uuid.Nil, err
|
return uuid.Nil, err
|
||||||
}
|
}
|
||||||
if environment == "" {
|
if environment == "" {
|
||||||
@@ -102,46 +105,31 @@ func cloneServiceRow(db *database.DB, sourceID uuid.UUID, targetProjectID uuid.U
|
|||||||
maintenance, basicAuth := serviceAccess(db, sourceID)
|
maintenance, basicAuth := serviceAccess(db, sourceID)
|
||||||
newID := uuid.New()
|
newID := uuid.New()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
// string() so pq sends text — []byte would go as bytea and fail ::jsonb.
|
|
||||||
volumesJSON := string(loadServiceVolumesJSON(db, sourceID))
|
|
||||||
|
|
||||||
_, err = db.Exec(
|
err = q.CloneServiceRow(ctx, sqlcdb.CloneServiceRowParams{
|
||||||
`INSERT INTO services
|
ID: newID,
|
||||||
(id, project_id, name, environment_id, service_type, source_type, source_url, image_name,
|
ProjectID: targetProjectID,
|
||||||
build_command, start_command, type, status, image, command, environment,
|
Name: name,
|
||||||
git_repo, git_branch, build_path, cpu, memory, replicas, port, domain,
|
EnvironmentID: environmentID,
|
||||||
healthcheck_path, restart_policy, volumes, maintenance_mode, basic_auth_users,
|
Environment: sql.NullString{String: environment, Valid: true},
|
||||||
builder, cpu_reserve, memory_reserve, static_build_cmd, static_dir,
|
MaintenanceMode: maintenance,
|
||||||
created_at, updated_at)
|
BasicAuthUsers: basicAuth,
|
||||||
SELECT $1, $2, $3, $4, service_type, source_type, source_url, image_name,
|
CreatedAt: sql.NullTime{Time: now, Valid: true},
|
||||||
build_command, start_command, type, 'stopped', image, command, $5,
|
ID_2: sourceID,
|
||||||
git_repo, git_branch, build_path, cpu, memory, replicas, port, domain,
|
})
|
||||||
healthcheck_path, restart_policy, $6::jsonb, $7, $8,
|
|
||||||
builder, cpu_reserve, memory_reserve, static_build_cmd, static_dir,
|
|
||||||
$9, $9
|
|
||||||
FROM services WHERE id = $10`,
|
|
||||||
newID, targetProjectID, name, environmentID, environment, volumesJSON,
|
|
||||||
maintenance, basicAuth, now, sourceID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uuid.Nil, err
|
return uuid.Nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := db.Exec(
|
if err := q.CloneServiceDomains(ctx, sqlcdb.CloneServiceDomainsParams{
|
||||||
`INSERT INTO service_domains (service_id, domain, is_default, cert_type)
|
ServiceID: newID, ServiceID_2: sourceID}); err != nil {
|
||||||
SELECT $1, domain, is_default, cert_type FROM service_domains WHERE service_id = $2`,
|
_ = q.DeleteServiceByID(ctx, newID)
|
||||||
newID, sourceID,
|
|
||||||
); err != nil {
|
|
||||||
_, _ = db.Exec(`DELETE FROM services WHERE id = $1`, newID)
|
|
||||||
return uuid.Nil, err
|
return uuid.Nil, err
|
||||||
}
|
}
|
||||||
// Variable values are copied as stored — ciphertext stays ciphertext.
|
// Variable values are copied as stored — ciphertext stays ciphertext.
|
||||||
if _, err := db.Exec(
|
if err := q.CloneServiceVariables(ctx, sqlcdb.CloneServiceVariablesParams{
|
||||||
`INSERT INTO environment_variables (id, service_id, key, value, is_secret)
|
ServiceID: newID, ServiceID_2: sourceID}); err != nil {
|
||||||
SELECT gen_random_uuid(), $1, key, value, is_secret FROM environment_variables WHERE service_id = $2`,
|
_ = q.DeleteServiceByID(ctx, newID)
|
||||||
newID, sourceID,
|
|
||||||
); err != nil {
|
|
||||||
_, _ = db.Exec(`DELETE FROM services WHERE id = $1`, newID)
|
|
||||||
return uuid.Nil, err
|
return uuid.Nil, err
|
||||||
}
|
}
|
||||||
return newID, nil
|
return newID, nil
|
||||||
@@ -187,11 +175,8 @@ func handleMoveService(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var count int
|
count, _ := sqlcdb.New(db.(*database.DB).DB).CountServicesByName(
|
||||||
_ = db.(*database.DB).QueryRow(
|
c.Request.Context(), sqlcdb.CountServicesByNameParams{ProjectID: req.ProjectID, Name: service.Name})
|
||||||
`SELECT COUNT(*) FROM services WHERE project_id = $1 AND name = $2`,
|
|
||||||
req.ProjectID, service.Name,
|
|
||||||
).Scan(&count)
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
c.JSON(http.StatusConflict, gin.H{"error": "A service with this name already exists in the target project", "code": "CONFLICT"})
|
c.JSON(http.StatusConflict, gin.H{"error": "A service with this name already exists in the target project", "code": "CONFLICT"})
|
||||||
return
|
return
|
||||||
@@ -207,15 +192,18 @@ func handleMoveService(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := db.(*database.DB).Exec(
|
n, err := sqlcdb.New(db.(*database.DB).DB).MoveServiceProject(
|
||||||
`UPDATE services SET project_id = $1, environment_id = $2, updated_at = $3 WHERE id = $4`,
|
c.Request.Context(), sqlcdb.MoveServiceProjectParams{
|
||||||
req.ProjectID, environmentID, time.Now(), serviceID,
|
ProjectID: req.ProjectID,
|
||||||
)
|
EnvironmentID: environmentID,
|
||||||
|
UpdatedAt: sql.NullTime{Time: time.Now(), Valid: true},
|
||||||
|
ID: serviceID,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to move service"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to move service"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if n, _ := res.RowsAffected(); n == 0 {
|
if n == 0 {
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": "Service not found", "code": "NOT_FOUND"})
|
c.JSON(http.StatusNotFound, gin.H{"error": "Service not found", "code": "NOT_FOUND"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -229,16 +217,10 @@ func ownsProject(db *database.DB, projectID uuid.UUID, userID string, isAdmin bo
|
|||||||
if isAdmin {
|
if isAdmin {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
var owner string
|
uid, err := uuid.Parse(userID)
|
||||||
err := db.QueryRow(`SELECT owner_id FROM projects WHERE id = $1`, projectID).Scan(&owner)
|
if err != nil {
|
||||||
return err == nil && owner == userID
|
return false
|
||||||
}
|
}
|
||||||
|
owner, err := sqlcdb.New(db.DB).GetProjectOwner(context.Background(), projectID)
|
||||||
// loadServiceVolumesJSON returns the raw stored mounts for a verbatim copy.
|
return err == nil && owner == uid
|
||||||
func loadServiceVolumesJSON(db *database.DB, serviceID uuid.UUID) []byte {
|
|
||||||
var raw []byte
|
|
||||||
if err := db.QueryRow(`SELECT volumes FROM services WHERE id = $1`, serviceID).Scan(&raw); err != nil || len(raw) == 0 {
|
|
||||||
return []byte("[]")
|
|
||||||
}
|
|
||||||
return raw
|
|
||||||
}
|
}
|
||||||
@@ -18,12 +18,16 @@ type Querier interface {
|
|||||||
AggregateNodeMetrics(ctx context.Context, arg AggregateNodeMetricsParams) ([]AggregateNodeMetricsRow, error)
|
AggregateNodeMetrics(ctx context.Context, arg AggregateNodeMetricsParams) ([]AggregateNodeMetricsRow, error)
|
||||||
ClearServiceDomainDefault(ctx context.Context, serviceID uuid.UUID) error
|
ClearServiceDomainDefault(ctx context.Context, serviceID uuid.UUID) error
|
||||||
ClearServiceNodePins(ctx context.Context, nodeID sql.NullString) (int64, error)
|
ClearServiceNodePins(ctx context.Context, nodeID sql.NullString) (int64, error)
|
||||||
|
CloneServiceDomains(ctx context.Context, arg CloneServiceDomainsParams) error
|
||||||
|
CloneServiceRow(ctx context.Context, arg CloneServiceRowParams) error
|
||||||
|
CloneServiceVariables(ctx context.Context, arg CloneServiceVariablesParams) error
|
||||||
CompleteCommand(ctx context.Context, arg CompleteCommandParams) (AgentCommand, error)
|
CompleteCommand(ctx context.Context, arg CompleteCommandParams) (AgentCommand, error)
|
||||||
CountDatabaseServicesByUserAndName(ctx context.Context, arg CountDatabaseServicesByUserAndNameParams) (int64, error)
|
CountDatabaseServicesByUserAndName(ctx context.Context, arg CountDatabaseServicesByUserAndNameParams) (int64, error)
|
||||||
CountDatabasesUsingBackupTarget(ctx context.Context, targetID sql.NullString) (int64, error)
|
CountDatabasesUsingBackupTarget(ctx context.Context, targetID sql.NullString) (int64, error)
|
||||||
CountEnvironmentServices(ctx context.Context, environmentID uuid.UUID) (int64, error)
|
CountEnvironmentServices(ctx context.Context, environmentID uuid.UUID) (int64, error)
|
||||||
CountProjectsByUser(ctx context.Context, arg CountProjectsByUserParams) (int64, error)
|
CountProjectsByUser(ctx context.Context, arg CountProjectsByUserParams) (int64, error)
|
||||||
CountServiceDomains(ctx context.Context, serviceID uuid.UUID) (int64, error)
|
CountServiceDomains(ctx context.Context, serviceID uuid.UUID) (int64, error)
|
||||||
|
CountServicesByName(ctx context.Context, arg CountServicesByNameParams) (int64, error)
|
||||||
CountServicesByProjectAndName(ctx context.Context, arg CountServicesByProjectAndNameParams) (int64, error)
|
CountServicesByProjectAndName(ctx context.Context, arg CountServicesByProjectAndNameParams) (int64, error)
|
||||||
CountUnreadNotificationsByUser(ctx context.Context, userID uuid.UUID) (int64, error)
|
CountUnreadNotificationsByUser(ctx context.Context, userID uuid.UUID) (int64, error)
|
||||||
CreateAgent(ctx context.Context, arg CreateAgentParams) (NodeAgent, error)
|
CreateAgent(ctx context.Context, arg CreateAgentParams) (NodeAgent, error)
|
||||||
@@ -54,6 +58,7 @@ type Querier interface {
|
|||||||
DeleteOutboundWebhookByIDAndUser(ctx context.Context, arg DeleteOutboundWebhookByIDAndUserParams) error
|
DeleteOutboundWebhookByIDAndUser(ctx context.Context, arg DeleteOutboundWebhookByIDAndUserParams) error
|
||||||
DeleteProjectByID(ctx context.Context, projectID uuid.UUID) (int64, error)
|
DeleteProjectByID(ctx context.Context, projectID uuid.UUID) (int64, error)
|
||||||
DeleteProjectEnvironment(ctx context.Context, arg DeleteProjectEnvironmentParams) error
|
DeleteProjectEnvironment(ctx context.Context, arg DeleteProjectEnvironmentParams) error
|
||||||
|
DeleteServiceByID(ctx context.Context, id uuid.UUID) error
|
||||||
DeleteServiceContainersOnAgent(ctx context.Context, arg DeleteServiceContainersOnAgentParams) error
|
DeleteServiceContainersOnAgent(ctx context.Context, arg DeleteServiceContainersOnAgentParams) error
|
||||||
DeleteServiceDomain(ctx context.Context, arg DeleteServiceDomainParams) (int64, error)
|
DeleteServiceDomain(ctx context.Context, arg DeleteServiceDomainParams) (int64, error)
|
||||||
DeleteUserInvite(ctx context.Context, id uuid.UUID) error
|
DeleteUserInvite(ctx context.Context, id uuid.UUID) error
|
||||||
@@ -76,12 +81,14 @@ type Querier interface {
|
|||||||
GetOutboundWebhookByIDAndUser(ctx context.Context, arg GetOutboundWebhookByIDAndUserParams) (OutboundWebhook, error)
|
GetOutboundWebhookByIDAndUser(ctx context.Context, arg GetOutboundWebhookByIDAndUserParams) (OutboundWebhook, error)
|
||||||
GetProjectByIDForUser(ctx context.Context, arg GetProjectByIDForUserParams) (Project, error)
|
GetProjectByIDForUser(ctx context.Context, arg GetProjectByIDForUserParams) (Project, error)
|
||||||
GetProjectEnvironmentByName(ctx context.Context, arg GetProjectEnvironmentByNameParams) (Environment, error)
|
GetProjectEnvironmentByName(ctx context.Context, arg GetProjectEnvironmentByNameParams) (Environment, error)
|
||||||
|
GetProjectOwner(ctx context.Context, id uuid.UUID) (uuid.UUID, error)
|
||||||
GetProjectOwnerByID(ctx context.Context, projectID uuid.UUID) (uuid.UUID, error)
|
GetProjectOwnerByID(ctx context.Context, projectID uuid.UUID) (uuid.UUID, error)
|
||||||
GetProjectOwnerID(ctx context.Context, id uuid.UUID) (uuid.UUID, error)
|
GetProjectOwnerID(ctx context.Context, id uuid.UUID) (uuid.UUID, error)
|
||||||
GetProjectRoleForUser(ctx context.Context, arg GetProjectRoleForUserParams) (string, error)
|
GetProjectRoleForUser(ctx context.Context, arg GetProjectRoleForUserParams) (string, error)
|
||||||
GetServiceAccess(ctx context.Context, id uuid.UUID) (GetServiceAccessRow, error)
|
GetServiceAccess(ctx context.Context, id uuid.UUID) (GetServiceAccessRow, error)
|
||||||
GetServiceDomainDefault(ctx context.Context, serviceID uuid.UUID) (string, error)
|
GetServiceDomainDefault(ctx context.Context, serviceID uuid.UUID) (string, error)
|
||||||
GetServiceDomainFirst(ctx context.Context, serviceID uuid.UUID) (string, error)
|
GetServiceDomainFirst(ctx context.Context, serviceID uuid.UUID) (string, error)
|
||||||
|
GetServiceEnvironment(ctx context.Context, id uuid.UUID) (string, error)
|
||||||
GetServicePlacementBrief(ctx context.Context, id uuid.UUID) (GetServicePlacementBriefRow, error)
|
GetServicePlacementBrief(ctx context.Context, id uuid.UUID) (GetServicePlacementBriefRow, error)
|
||||||
GetServiceTemplateByID(ctx context.Context, id string) (ServiceTemplate, error)
|
GetServiceTemplateByID(ctx context.Context, id string) (ServiceTemplate, error)
|
||||||
GetUserInviteByTokenHash(ctx context.Context, tokenHash string) (UserInvite, error)
|
GetUserInviteByTokenHash(ctx context.Context, tokenHash string) (UserInvite, error)
|
||||||
@@ -135,6 +142,7 @@ type Querier interface {
|
|||||||
MarkAllNotificationsReadByUser(ctx context.Context, arg MarkAllNotificationsReadByUserParams) error
|
MarkAllNotificationsReadByUser(ctx context.Context, arg MarkAllNotificationsReadByUserParams) error
|
||||||
MarkNotificationReadByIDAndUser(ctx context.Context, arg MarkNotificationReadByIDAndUserParams) error
|
MarkNotificationReadByIDAndUser(ctx context.Context, arg MarkNotificationReadByIDAndUserParams) error
|
||||||
MarkUserInviteUsed(ctx context.Context, arg MarkUserInviteUsedParams) error
|
MarkUserInviteUsed(ctx context.Context, arg MarkUserInviteUsedParams) error
|
||||||
|
MoveServiceProject(ctx context.Context, arg MoveServiceProjectParams) (int64, error)
|
||||||
// Resource-aware: lowest memory utilisation first, then cpu, then container
|
// Resource-aware: lowest memory utilisation first, then cpu, then container
|
||||||
// count. Agents without telemetry sort last (NULL → worst score).
|
// count. Agents without telemetry sort last (NULL → worst score).
|
||||||
PickLeastLoadedAgent(ctx context.Context) (string, error)
|
PickLeastLoadedAgent(ctx context.Context) (string, error)
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: service_ops.sql
|
||||||
|
|
||||||
|
package sqlcdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const cloneServiceDomains = `-- name: CloneServiceDomains :exec
|
||||||
|
INSERT INTO service_domains (service_id, domain, is_default, cert_type)
|
||||||
|
SELECT $1, domain, is_default, cert_type FROM service_domains sd WHERE sd.service_id = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type CloneServiceDomainsParams struct {
|
||||||
|
ServiceID uuid.UUID `json:"service_id"`
|
||||||
|
ServiceID_2 uuid.UUID `json:"service_id_2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CloneServiceDomains(ctx context.Context, arg CloneServiceDomainsParams) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, cloneServiceDomains, arg.ServiceID, arg.ServiceID_2)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloneServiceRow = `-- name: CloneServiceRow :exec
|
||||||
|
INSERT INTO services
|
||||||
|
(id, project_id, name, environment_id, service_type, source_type, source_url, image_name,
|
||||||
|
build_command, start_command, type, status, image, command, environment,
|
||||||
|
git_repo, git_branch, build_path, cpu, memory, replicas, port, domain,
|
||||||
|
healthcheck_path, restart_policy, volumes, maintenance_mode, basic_auth_users,
|
||||||
|
builder, cpu_reserve, memory_reserve, static_build_cmd, static_dir,
|
||||||
|
traefik_labels, created_at, updated_at)
|
||||||
|
SELECT $1, $2, $3, $4, service_type, source_type, source_url, image_name,
|
||||||
|
build_command, start_command, type, 'stopped', image, command, $5,
|
||||||
|
git_repo, git_branch, build_path, cpu, memory, replicas, port, domain,
|
||||||
|
healthcheck_path, restart_policy, volumes, $6, $7,
|
||||||
|
builder, cpu_reserve, memory_reserve, static_build_cmd, static_dir,
|
||||||
|
traefik_labels, $8, $8
|
||||||
|
FROM services s WHERE s.id = $9
|
||||||
|
`
|
||||||
|
|
||||||
|
type CloneServiceRowParams struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
ProjectID uuid.UUID `json:"project_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
EnvironmentID uuid.UUID `json:"environment_id"`
|
||||||
|
Environment sql.NullString `json:"environment"`
|
||||||
|
MaintenanceMode bool `json:"maintenance_mode"`
|
||||||
|
BasicAuthUsers string `json:"basic_auth_users"`
|
||||||
|
CreatedAt sql.NullTime `json:"created_at"`
|
||||||
|
ID_2 uuid.UUID `json:"id_2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CloneServiceRow(ctx context.Context, arg CloneServiceRowParams) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, cloneServiceRow,
|
||||||
|
arg.ID,
|
||||||
|
arg.ProjectID,
|
||||||
|
arg.Name,
|
||||||
|
arg.EnvironmentID,
|
||||||
|
arg.Environment,
|
||||||
|
arg.MaintenanceMode,
|
||||||
|
arg.BasicAuthUsers,
|
||||||
|
arg.CreatedAt,
|
||||||
|
arg.ID_2,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloneServiceVariables = `-- name: CloneServiceVariables :exec
|
||||||
|
INSERT INTO environment_variables (id, service_id, key, value, is_secret)
|
||||||
|
SELECT gen_random_uuid(), $1, key, value, is_secret FROM environment_variables ev WHERE ev.service_id = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type CloneServiceVariablesParams struct {
|
||||||
|
ServiceID uuid.UUID `json:"service_id"`
|
||||||
|
ServiceID_2 uuid.UUID `json:"service_id_2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CloneServiceVariables(ctx context.Context, arg CloneServiceVariablesParams) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, cloneServiceVariables, arg.ServiceID, arg.ServiceID_2)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const countServicesByName = `-- name: CountServicesByName :one
|
||||||
|
SELECT COUNT(*) FROM services WHERE project_id = $1 AND name = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type CountServicesByNameParams struct {
|
||||||
|
ProjectID uuid.UUID `json:"project_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CountServicesByName(ctx context.Context, arg CountServicesByNameParams) (int64, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, countServicesByName, arg.ProjectID, arg.Name)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteServiceByID = `-- name: DeleteServiceByID :exec
|
||||||
|
DELETE FROM services WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteServiceByID(ctx context.Context, id uuid.UUID) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, deleteServiceByID, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getProjectOwner = `-- name: GetProjectOwner :one
|
||||||
|
SELECT owner_id FROM projects WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetProjectOwner(ctx context.Context, id uuid.UUID) (uuid.UUID, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, getProjectOwner, id)
|
||||||
|
var owner_id uuid.UUID
|
||||||
|
err := row.Scan(&owner_id)
|
||||||
|
return owner_id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getServiceEnvironment = `-- name: GetServiceEnvironment :one
|
||||||
|
SELECT COALESCE(environment, '') FROM services WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetServiceEnvironment(ctx context.Context, id uuid.UUID) (string, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, getServiceEnvironment, id)
|
||||||
|
var environment string
|
||||||
|
err := row.Scan(&environment)
|
||||||
|
return environment, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveServiceProject = `-- name: MoveServiceProject :execrows
|
||||||
|
UPDATE services SET project_id = $1, environment_id = $2, updated_at = $3 WHERE id = $4
|
||||||
|
`
|
||||||
|
|
||||||
|
type MoveServiceProjectParams struct {
|
||||||
|
ProjectID uuid.UUID `json:"project_id"`
|
||||||
|
EnvironmentID uuid.UUID `json:"environment_id"`
|
||||||
|
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) MoveServiceProject(ctx context.Context, arg MoveServiceProjectParams) (int64, error) {
|
||||||
|
result, err := q.db.ExecContext(ctx, moveServiceProject,
|
||||||
|
arg.ProjectID,
|
||||||
|
arg.EnvironmentID,
|
||||||
|
arg.UpdatedAt,
|
||||||
|
arg.ID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return result.RowsAffected()
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
-- name: CountServicesByName :one
|
||||||
|
SELECT COUNT(*) FROM services WHERE project_id = $1 AND name = $2;
|
||||||
|
|
||||||
|
-- name: GetServiceEnvironment :one
|
||||||
|
SELECT COALESCE(environment, '') FROM services WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: CloneServiceRow :exec
|
||||||
|
INSERT INTO services
|
||||||
|
(id, project_id, name, environment_id, service_type, source_type, source_url, image_name,
|
||||||
|
build_command, start_command, type, status, image, command, environment,
|
||||||
|
git_repo, git_branch, build_path, cpu, memory, replicas, port, domain,
|
||||||
|
healthcheck_path, restart_policy, volumes, maintenance_mode, basic_auth_users,
|
||||||
|
builder, cpu_reserve, memory_reserve, static_build_cmd, static_dir,
|
||||||
|
traefik_labels, created_at, updated_at)
|
||||||
|
SELECT $1, $2, $3, $4, service_type, source_type, source_url, image_name,
|
||||||
|
build_command, start_command, type, 'stopped', image, command, $5,
|
||||||
|
git_repo, git_branch, build_path, cpu, memory, replicas, port, domain,
|
||||||
|
healthcheck_path, restart_policy, volumes, $6, $7,
|
||||||
|
builder, cpu_reserve, memory_reserve, static_build_cmd, static_dir,
|
||||||
|
traefik_labels, $8, $8
|
||||||
|
FROM services s WHERE s.id = $9;
|
||||||
|
|
||||||
|
-- name: CloneServiceDomains :exec
|
||||||
|
INSERT INTO service_domains (service_id, domain, is_default, cert_type)
|
||||||
|
SELECT $1, domain, is_default, cert_type FROM service_domains sd WHERE sd.service_id = $2;
|
||||||
|
|
||||||
|
-- name: CloneServiceVariables :exec
|
||||||
|
INSERT INTO environment_variables (id, service_id, key, value, is_secret)
|
||||||
|
SELECT gen_random_uuid(), $1, key, value, is_secret FROM environment_variables ev WHERE ev.service_id = $2;
|
||||||
|
|
||||||
|
-- name: DeleteServiceByID :exec
|
||||||
|
DELETE FROM services WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: MoveServiceProject :execrows
|
||||||
|
UPDATE services SET project_id = $1, environment_id = $2, updated_at = $3 WHERE id = $4;
|
||||||
|
|
||||||
|
-- name: GetProjectOwner :one
|
||||||
|
SELECT owner_id FROM projects WHERE id = $1;
|
||||||
Reference in new issue
Block a user