Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deployment/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ services:
networks:
- default
container_name: s3
image: bitnami/minio:2025.4.3
image: bitnamilegacy/minio:2025.7.23
ports:
- 3902:3902
- 2903:2903
Expand Down
86 changes: 45 additions & 41 deletions go/apps/ctrl/services/deployment/deploy_workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/unkeyed/unkey/go/gen/proto/metald/v1/metaldv1connect"
partitionv1 "github.com/unkeyed/unkey/go/gen/proto/partition/v1"
"github.com/unkeyed/unkey/go/pkg/db"
"github.com/unkeyed/unkey/go/pkg/git"
"github.com/unkeyed/unkey/go/pkg/hydra"
"github.com/unkeyed/unkey/go/pkg/otel/logging"
partitiondb "github.com/unkeyed/unkey/go/pkg/partition/db"
Expand Down Expand Up @@ -40,6 +39,12 @@ type DeployWorkflowConfig struct {

// NewDeployWorkflow creates a new deploy workflow instance
func NewDeployWorkflow(cfg DeployWorkflowConfig) *DeployWorkflow {

cfg.Logger.Info("Initializing deploy workflow",
"metald_backend", cfg.MetaldBackend,
"default_domain", cfg.DefaultDomain,
"is_running_docker", cfg.IsRunningDocker,
)
// Create the appropriate deployment backend
deploymentBackend, err := NewDeploymentBackend(cfg.MetalD, cfg.MetaldBackend, cfg.Logger, cfg.IsRunningDocker)
if err != nil {
Expand Down Expand Up @@ -88,8 +93,34 @@ func (w *DeployWorkflow) Run(ctx hydra.WorkflowContext, req *DeployRequest) erro
"workspace_id", req.WorkspaceID,
"project_id", req.ProjectID,
)

workspace, err := hydra.Step(ctx, "get-workspace", func(stepCtx context.Context) (db.Workspace, error) {
return db.Query.FindWorkspaceByID(stepCtx, w.db.RW(), req.WorkspaceID)
})
if err != nil {
return err
}
project, err := hydra.Step(ctx, "get-project", func(stepCtx context.Context) (db.FindProjectByIdRow, error) {
return db.Query.FindProjectById(stepCtx, w.db.RW(), req.ProjectID)
})
if err != nil {
return err
}
environment, err := hydra.Step(ctx, "get-environment", func(stepCtx context.Context) (db.FindEnvironmentByIdRow, error) {
return db.Query.FindEnvironmentById(stepCtx, w.db.RW(), req.EnvironmentID)
})
if err != nil {
return err
}
deployment, err := hydra.Step(ctx, "get-deployment", func(stepCtx context.Context) (db.FindDeploymentByIdRow, error) {
return db.Query.FindDeploymentById(stepCtx, w.db.RW(), req.DeploymentID)
})
if err != nil {
return err
}
Comment thread
chronark marked this conversation as resolved.

// Log deployment pending
err := hydra.StepVoid(ctx, "log-deployment-pending", func(stepCtx context.Context) error {
err = hydra.StepVoid(ctx, "log-deployment-pending", func(stepCtx context.Context) error {
return db.Query.InsertDeploymentStep(stepCtx, w.db.RW(), db.InsertDeploymentStepParams{
WorkspaceID: req.WorkspaceID,
ProjectID: req.ProjectID,
Expand Down Expand Up @@ -119,7 +150,7 @@ func (w *DeployWorkflow) Run(ctx hydra.WorkflowContext, req *DeployRequest) erro
return err
}

deployment, err := hydra.Step(ctx, "create-deployment", func(stepCtx context.Context) (*metaldv1.CreateDeploymentResponse, error) {
metaldDeployment, err := hydra.Step(ctx, "create-deployment", func(stepCtx context.Context) (*metaldv1.CreateDeploymentResponse, error) {
if w.deploymentBackend == nil {
return nil, fmt.Errorf("deployment backend not initialized")
}
Expand All @@ -146,7 +177,7 @@ func (w *DeployWorkflow) Run(ctx hydra.WorkflowContext, req *DeployRequest) erro
return err
}

w.logger.Info("deployment created", "deployment_id", req.DeploymentID, "vm_count", len(deployment.GetVmIds()))
w.logger.Info("deployment created", "deployment_id", req.DeploymentID, "vm_count", len(metaldDeployment.GetVmIds()))

// Update version status to deploying
_, err = hydra.Step(ctx, "update-version-deploying", func(stepCtx context.Context) (*struct{}, error) {
Expand Down Expand Up @@ -243,46 +274,19 @@ func (w *DeployWorkflow) Run(ctx hydra.WorkflowContext, req *DeployRequest) erro
if err != nil {
return err
}

allDomains, err := hydra.Step(ctx, "generate-all-domains", func(stepCtx context.Context) ([]string, error) {
var domains []string

// Generate auto-generated hostname for this deployment
gitInfo := git.GetInfo()
branch := "main" // Default branch
identifier := req.DeploymentID // Use full version ID as identifier

if gitInfo.IsRepo {
if gitInfo.Branch != "" {
branch = gitInfo.Branch
}
if gitInfo.CommitSHA != "" {
identifier = gitInfo.CommitSHA
}
}

// Generate primary hostname: branch-identifier-workspace.domain
cleanIdentifier := strings.ToLower(strings.ReplaceAll(identifier, "_", "-"))
cleanBranch := strings.ToLower(strings.ReplaceAll(branch, "/", "-"))
cleanWorkspaceID := strings.ToLower(req.WorkspaceID)
autoGeneratedHostname := fmt.Sprintf("%s-%s-%s.%s", cleanBranch, cleanIdentifier, cleanWorkspaceID, w.defaultDomain)
domains = append(domains, autoGeneratedHostname)

w.logger.Info("generated all domains",
"deployment_id", req.DeploymentID,
"total_domains", len(domains),
"domains", domains,
)

return domains, nil
})
if err != nil {
return err
}
allDomains := buildDomains(
workspace.Slug,
project.Slug,
environment.Slug,
deployment.GitCommitSha.String,
deployment.GitBranch.String,
w.defaultDomain,
)

// Create database entries for all domains
err = hydra.StepVoid(ctx, "create-domain-entries", func(stepCtx context.Context) error {
// Prepare bulk insert parameters
//
domainParams := make([]db.InsertDomainParams, 0, len(allDomains))
currentTime := time.Now().UnixMilli()

Expand All @@ -296,7 +300,7 @@ func (w *DeployWorkflow) Run(ctx hydra.WorkflowContext, req *DeployRequest) erro
DeploymentID: sql.NullString{Valid: true, String: req.DeploymentID},
CreatedAt: currentTime,
UpdatedAt: sql.NullInt64{Valid: true, Int64: currentTime},
Type: db.DomainsTypeCustom,
Type: db.DomainsTypeWildcard,
})
}

Expand Down
70 changes: 70 additions & 0 deletions go/apps/ctrl/services/deployment/domains.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package deployment

import (
"fmt"
"regexp"
"strings"
)

// buildDomains looks at the deployment and returns a list of domains
// that should be assigned to the deployment.
//
// We want these domains per deployment
// - `<projectslug>-git-<gitsha>-<workspaceslug>.unkey.app` (this never gets reassigned)
// - `<projectslug>-git-<branchname>-<workspaceslug>.unkey.app` (this needs to point to the latest deployment of that branch, sluggify the branch name )
// - `<projectslug>-<environmentslug>-<workspaceslug>.unkey.app` (this needs to point to the latest deployment of that environment and be rolled back)
func buildDomains(workspaceSlug, projectSlug, environmentSlug, gitSha, branchName, apex string) []string {

var domains []string

if gitSha != "" {
domains = append(
domains,
fmt.Sprintf("%s-git-%s-%s.%s", projectSlug, gitSha[:7], workspaceSlug, apex),
)
}
Comment thread
chronark marked this conversation as resolved.

if branchName != "" {
domains = append(
domains,
fmt.Sprintf("%s-git-%s-%s.%s", projectSlug, sluggify(branchName), workspaceSlug, apex),
)
}

domains = append(
domains,
fmt.Sprintf("%s-%s-%s.%s", projectSlug, environmentSlug, workspaceSlug, apex),
)
return domains
Comment thread
chronark marked this conversation as resolved.

}

var nonAlphanumericRegex = regexp.MustCompile(`[^a-zA-Z0-9\s]`)
var multipleSpacesRegex = regexp.MustCompile(`\s+`)

func sluggify(s string) string {
// Trim whitespace
s = strings.TrimSpace(s)

// Remove all non-alphanumeric characters except spaces
s = nonAlphanumericRegex.ReplaceAllString(s, "")
Comment thread
chronark marked this conversation as resolved.
Outdated

// Replace multiple spaces with single space
s = multipleSpacesRegex.ReplaceAllString(s, " ")

// Replace spaces with hyphens
s = strings.ReplaceAll(s, " ", "-")

// Convert to lowercase
s = strings.ToLower(s)

// Limit to 80 characters
if len(s) > 80 {
s = s[:80]
}

// Remove trailing hyphen if present
s = strings.TrimSuffix(s, "-")

return s
}
2 changes: 2 additions & 0 deletions go/k8s/manifests/ctrl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ spec:
value: "false"
- name: UNKEY_METALD_BACKEND
value: "k8s"
- name: UNKEY_DEFAULT_DOMAIN
value: "unkey.local"
command: ["/unkey", "run", "ctrl"]
initContainers:
- name: wait-for-dependencies
Expand Down
2 changes: 1 addition & 1 deletion go/k8s/manifests/s3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ spec:
spec:
containers:
- name: minio
image: bitnami/minio:2025.7.23
image: bitnamilegacy/minio:2025.7.23
ports:
- containerPort: 9000
name: api
Expand Down
43 changes: 43 additions & 0 deletions go/pkg/db/environment_find_by_id.sql_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions go/pkg/db/querier_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions go/pkg/db/queries/environment_find_by_id.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- name: FindEnvironmentById :one
SELECT id, workspace_id, project_id, slug, description
FROM environments
WHERE id = sqlc.arg(id);
Loading