mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-20 09:14:16 +00:00
add new upcloud cli deploy
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
//go:embed systemd/appview.service.tmpl
|
||||
var appviewServiceTmpl string
|
||||
|
||||
//go:embed systemd/hold.service.tmpl
|
||||
var holdServiceTmpl string
|
||||
|
||||
//go:embed configs/appview.yaml.tmpl
|
||||
var appviewConfigTmpl string
|
||||
|
||||
//go:embed configs/hold.yaml.tmpl
|
||||
var holdConfigTmpl string
|
||||
|
||||
//go:embed configs/cloudinit.sh.tmpl
|
||||
var cloudInitTmpl string
|
||||
|
||||
// ConfigValues holds values injected into config YAML templates.
|
||||
// Only truly dynamic/computed values belong here — deployment-specific
|
||||
// values like client_name, owner_did, etc. are literal in the templates.
|
||||
type ConfigValues struct {
|
||||
// S3 / Object Storage
|
||||
S3Endpoint string
|
||||
S3Region string
|
||||
S3Bucket string
|
||||
S3AccessKey string
|
||||
S3SecretKey string
|
||||
|
||||
// Infrastructure (computed from zone + config)
|
||||
Zone string // e.g. "us-chi1"
|
||||
HoldDomain string // e.g. "us-chi1.cove.seamark.dev"
|
||||
HoldDid string // e.g. "did:web:us-chi1.cove.seamark.dev"
|
||||
BasePath string // e.g. "/var/lib/seamark"
|
||||
}
|
||||
|
||||
// renderConfig executes a Go template with the given values.
|
||||
func renderConfig(tmplStr string, vals *ConfigValues) (string, error) {
|
||||
t, err := template.New("config").Parse(tmplStr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse config template: %w", err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := t.Execute(&buf, vals); err != nil {
|
||||
return "", fmt.Errorf("render config template: %w", err)
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// serviceUnitParams holds values for rendering systemd service unit templates.
|
||||
type serviceUnitParams struct {
|
||||
DisplayName string // e.g. "Seamark"
|
||||
User string // e.g. "seamark"
|
||||
BinaryPath string // e.g. "/opt/seamark/bin/seamark-appview"
|
||||
ConfigPath string // e.g. "/etc/seamark/appview.yaml"
|
||||
DataDir string // e.g. "/var/lib/seamark"
|
||||
ServiceName string // e.g. "seamark-appview"
|
||||
}
|
||||
|
||||
func renderServiceUnit(tmplStr string, p serviceUnitParams) (string, error) {
|
||||
t, err := template.New("service").Parse(tmplStr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse service template: %w", err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := t.Execute(&buf, p); err != nil {
|
||||
return "", fmt.Errorf("render service template: %w", err)
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// generateAppviewCloudInit generates the cloud-init user-data script for the appview server.
|
||||
func generateAppviewCloudInit(cfg *InfraConfig, vals *ConfigValues, goVersion string) (string, error) {
|
||||
naming := cfg.Naming()
|
||||
|
||||
configYAML, err := renderConfig(appviewConfigTmpl, vals)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("appview config: %w", err)
|
||||
}
|
||||
|
||||
serviceUnit, err := renderServiceUnit(appviewServiceTmpl, serviceUnitParams{
|
||||
DisplayName: naming.DisplayName(),
|
||||
User: naming.SystemUser(),
|
||||
BinaryPath: naming.InstallDir() + "/bin/" + naming.Appview(),
|
||||
ConfigPath: naming.AppviewConfigPath(),
|
||||
DataDir: naming.BasePath(),
|
||||
ServiceName: naming.Appview(),
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("appview service unit: %w", err)
|
||||
}
|
||||
|
||||
return generateCloudInit(cloudInitParams{
|
||||
GoVersion: goVersion,
|
||||
BinaryName: naming.Appview(),
|
||||
BuildCmd: "appview",
|
||||
ServiceUnit: serviceUnit,
|
||||
ConfigYAML: configYAML,
|
||||
ConfigPath: naming.AppviewConfigPath(),
|
||||
ServiceName: naming.Appview(),
|
||||
DataDir: naming.BasePath(),
|
||||
RepoURL: cfg.RepoURL,
|
||||
RepoBranch: cfg.RepoBranch,
|
||||
InstallDir: naming.InstallDir(),
|
||||
SystemUser: naming.SystemUser(),
|
||||
ConfigDir: naming.ConfigDir(),
|
||||
LogFile: naming.LogFile(),
|
||||
DisplayName: naming.DisplayName(),
|
||||
})
|
||||
}
|
||||
|
||||
// generateHoldCloudInit generates the cloud-init user-data script for the hold server.
|
||||
func generateHoldCloudInit(cfg *InfraConfig, vals *ConfigValues, goVersion string) (string, error) {
|
||||
naming := cfg.Naming()
|
||||
|
||||
configYAML, err := renderConfig(holdConfigTmpl, vals)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("hold config: %w", err)
|
||||
}
|
||||
|
||||
serviceUnit, err := renderServiceUnit(holdServiceTmpl, serviceUnitParams{
|
||||
DisplayName: naming.DisplayName(),
|
||||
User: naming.SystemUser(),
|
||||
BinaryPath: naming.InstallDir() + "/bin/" + naming.Hold(),
|
||||
ConfigPath: naming.HoldConfigPath(),
|
||||
DataDir: naming.BasePath(),
|
||||
ServiceName: naming.Hold(),
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("hold service unit: %w", err)
|
||||
}
|
||||
|
||||
return generateCloudInit(cloudInitParams{
|
||||
GoVersion: goVersion,
|
||||
BinaryName: naming.Hold(),
|
||||
BuildCmd: "hold",
|
||||
ServiceUnit: serviceUnit,
|
||||
ConfigYAML: configYAML,
|
||||
ConfigPath: naming.HoldConfigPath(),
|
||||
ServiceName: naming.Hold(),
|
||||
DataDir: naming.BasePath(),
|
||||
RepoURL: cfg.RepoURL,
|
||||
RepoBranch: cfg.RepoBranch,
|
||||
InstallDir: naming.InstallDir(),
|
||||
SystemUser: naming.SystemUser(),
|
||||
ConfigDir: naming.ConfigDir(),
|
||||
LogFile: naming.LogFile(),
|
||||
DisplayName: naming.DisplayName(),
|
||||
})
|
||||
}
|
||||
|
||||
type cloudInitParams struct {
|
||||
GoVersion string
|
||||
BinaryName string
|
||||
BuildCmd string
|
||||
ServiceUnit string
|
||||
ConfigYAML string
|
||||
ConfigPath string
|
||||
ServiceName string
|
||||
DataDir string
|
||||
RepoURL string
|
||||
RepoBranch string
|
||||
InstallDir string
|
||||
SystemUser string
|
||||
ConfigDir string
|
||||
LogFile string
|
||||
DisplayName string
|
||||
}
|
||||
|
||||
func generateCloudInit(p cloudInitParams) (string, error) {
|
||||
// Escape single quotes in embedded content for heredoc safety
|
||||
p.ServiceUnit = strings.ReplaceAll(p.ServiceUnit, "'", "'\\''")
|
||||
p.ConfigYAML = strings.ReplaceAll(p.ConfigYAML, "'", "'\\''")
|
||||
|
||||
t, err := template.New("cloudinit").Parse(cloudInitTmpl)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse cloudinit template: %w", err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := t.Execute(&buf, p); err != nil {
|
||||
return "", fmt.Errorf("render cloudinit template: %w", err)
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user