deploy

package
v1.2.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package deploy provides deployment management for the nSelf CLI. This file implements the blue-green deploy strategy adapter (T06).

Blue-green deploys:

  • Spin up a "green" stack alongside the live "blue" stack.
  • Run health checks on green.
  • Flip Nginx upstream weights from blue → green (100% flip, no canary phase).
  • Drain blue connections (60s grace via the bluegreen package).
  • Tear down blue.
  • On green failure: abort, keep blue running, log error.

This file is the strategy-path adapter called when the user passes --strategy=blue-green. It delegates all orchestration to the internal bluegreen package and writes outcome to .nself/state/deploy.json.

Package deploy provides deployment management for the nSelf CLI. This file implements the canary deploy strategy adapter (T06).

Canary deploys:

  • Spin up a canary (green) stack alongside the live (blue) stack.
  • Route N% of traffic to green via Nginx weighted upstream.
  • Monitor health during a configurable soak window (default 300s / 5min).
  • On healthy soak: gradually shift traffic 10% → 50% → 100%.
  • On unhealthy soak: revert canary to 0%, tear down green stack, log.

This file is the strategy-path adapter called when the user passes --strategy=canary. It delegates all orchestration to the internal bluegreen package and writes outcome to .nself/state/deploy.json.

Package deploy provides deployment orchestration for nSelf projects. This file implements secrets push over SSH using scp (G-003 / ops-profile).

Purpose: Copy a local .env file to a remote deploy host without echoing values. Inputs: SSHConfig (host + key path), PushSecretsOptions (target, paths, dry-run). Outputs: Remote ~/app/.env written; nothing secret reaches stdout. Constraints: scp must be in PATH; SSH key must be pre-installed on remote. SPORT: deploy subsystem — F08-SERVICE-INVENTORY.md

Package deploy provides deployment management commands for the nSelf CLI. This file implements the SLO-triggered rollback path (S88d.T05).

The SLO watcher (slo-watcher.ts in ping_api) calls:

nself deploy --rollback --service <service> --key <deploy-key>

This package handles that invocation: validates the deploy key, logs to np_auditlog_events, runs the rollback, and returns exit 0 on success or non-zero on failure.

Package deploy provides deployment management for the nSelf CLI. This file implements the SSH deploy helper used by 'nself deploy --env staging|prod' (G-003).

Required env vars:

NSELF_DEPLOY_HOST   - Remote host in user@host:/remote/path format
NSELF_DEPLOY_USER   - SSH user (overridden by the user@host prefix when set)
NSELF_DEPLOY_KEY_PATH - Path to SSH private key (default: ~/.ssh/id_ed25519)

Package deploy provides deployment management for the nSelf CLI. This file manages the unified deploy state file at .nself/state/deploy.json. It tracks which strategy was last used, its outcome, and provides the rollback target for `nself deploy rollback`.

Index

Constants

View Source
const DeployStateFile = ".nself/state/deploy.json"

DeployStateFile is the path relative to project root where deploy state is persisted. All deploy strategies (rolling, blue-green, canary) write to this file.

Variables

This section is empty.

Functions

func DeployViaSsh added in v1.1.1

func DeployViaSsh(ctx context.Context, cfg SSHConfig, composePath string) error

DeployViaSsh copies the compose file to the remote host via rsync, pulls updated images, and runs 'docker compose up -d' on the remote. If cfg.Follow is true, it streams 'docker compose logs --follow' until the context is cancelled.

Steps:

  1. rsync composePath to remote:/tmp/nself-compose.yml
  2. ssh exec "docker compose -f /tmp/nself-compose.yml pull"
  3. ssh exec "docker compose -f /tmp/nself-compose.yml up -d"
  4. if follow: stream "docker compose -f /tmp/nself-compose.yml logs --follow"

func PushSecrets added in v1.1.11

func PushSecrets(ctx context.Context, cfg SSHConfig, opts PushSecretsOptions) error

PushSecrets copies a local .env file to the remote deploy host over SSH using scp.

Secret values are never printed to stdout; only the target path and host are logged. The operation is idempotent: re-running safely overwrites the remote file.

Resolution order for EnvFile (when not explicitly set):

  1. {ProjectRoot}/.env.{Target}
  2. {ProjectRoot}/.env

The remote host is extracted from SSHConfig.Host which may be:

  • "user@host" or "host" (RemotePath used as-is)
  • "user@host:/remote/path" (path component ignored; RemotePath wins)

func RemoteDockerExecCommand added in v1.2.1

func RemoteDockerExecCommand(container string, args ...string) string

RemoteDockerExecCommand builds the shell command string for `docker exec <container> <args...>` run on the remote host. Arguments are shell-quoted individually so container names/args containing spaces are passed through safely.

func RunRemoteCommand added in v1.2.1

func RunRemoteCommand(ctx context.Context, rt RemoteTarget, command string) (string, error)

RunRemoteCommand runs command on the remote target via SSH and returns combined stdout+stderr. Errors are wrapped with the remote target and command for easy diagnosis; callers that need to detect "command not found on an older CLI" (gap #16, version drift) should inspect the returned error text for the exec/ssh "command not found" markers.

func SaveDeployState added in v1.0.16

func SaveDeployState(projectRoot string, s StrategyState) error

SaveDeployState writes the deploy state to .nself/state/deploy.json. The file is written atomically via a temp file + rename to avoid partial reads. Permissions are 0600 because deploy state contains hostnames and error context.

Types

type AuditEvent

type AuditEvent struct {
	EventType    string    `json:"event_type"`
	Service      string    `json:"service"`
	Environment  string    `json:"environment"`
	Reason       string    `json:"reason"`
	Outcome      string    `json:"outcome"`
	PriorVersion string    `json:"prior_version,omitempty"`
	Error        string    `json:"error,omitempty"`
	TriggeredBy  string    `json:"triggered_by"`
	Timestamp    time.Time `json:"timestamp"`
}

AuditEvent is written to np_auditlog_events on rollback.

type BlueGreenConfig added in v1.0.16

type BlueGreenConfig struct {
	// ProjectRoot is the nSelf project root (contains docker-compose.yml).
	ProjectRoot string

	// Target is the deploy target: local, staging, prod.
	Target string

	// DryRun prints steps without executing them.
	DryRun bool

	// HealthTimeoutSec overrides the default 30-second health check timeout.
	// Zero means use the default.
	HealthTimeoutSec int

	// ForceMigration disables the migration compatibility check and performs a
	// full blue-green flip even when backward-incompatible migrations are pending.
	ForceMigration bool
}

BlueGreenConfig holds the parameters for a blue-green deploy.

type BlueGreenResult added in v1.0.16

type BlueGreenResult struct {
	// Success is true when the deploy completed without error.
	Success bool

	// Steps is the ordered list of deploy steps with their status.
	Steps []bluegreen.DeployStep

	// Duration is how long the deploy took.
	Duration time.Duration

	// RolledBack is true when an automatic rollback was triggered.
	RolledBack bool

	// Error is set on failure.
	Error string
}

BlueGreenResult is the outcome of a blue-green deploy.

func RunBlueGreen added in v1.0.16

func RunBlueGreen(ctx context.Context, cfg BlueGreenConfig) BlueGreenResult

RunBlueGreen executes a blue-green deploy:

  1. Spins up the green stack alongside blue.
  2. Health-checks green.
  3. Flips Nginx upstream to 100% green (no canary phase).
  4. Health-checks green at 100%.
  5. Stops blue.
  6. Persists state to .nself/state/deploy.json.

On green failure: aborts immediately, keeps blue running, returns error.

type CanaryConfig added in v1.0.16

type CanaryConfig struct {
	// ProjectRoot is the nSelf project root (contains docker-compose.yml).
	ProjectRoot string

	// Target is the deploy target: local, staging, prod.
	Target string

	// InitialPercent is the initial canary traffic percentage (1-99).
	// Defaults to 10 when zero.
	InitialPercent int

	// SoakMinutes is the canary soak period in minutes. Defaults to 5.
	SoakMinutes int

	// ErrorThresholdPct is the error rate percentage that triggers auto-rollback.
	// Defaults to 1.0.
	ErrorThresholdPct float64

	// HealthTimeoutSec overrides the default 30-second health check timeout.
	// Zero means use the default.
	HealthTimeoutSec int

	// ForceMigration disables the migration compatibility check.
	// Required when a migration is not backward-compatible with canary traffic.
	ForceMigration bool

	// DryRun prints steps without executing them.
	DryRun bool
}

CanaryConfig holds the parameters for a canary deploy.

type CanaryResult added in v1.0.16

type CanaryResult struct {
	// Success is true when the deploy completed without error.
	Success bool

	// Steps is the ordered list of deploy steps with their status.
	Steps []bluegreen.DeployStep

	// Duration is how long the deploy took.
	Duration time.Duration

	// FinalPercent is the final canary traffic percentage (100 on success, 0 on rollback).
	FinalPercent int

	// RolledBack is true when an auto-rollback was triggered during the soak.
	RolledBack bool

	// Error is set on failure.
	Error string
}

CanaryResult is the outcome of a canary deploy.

func RunCanary added in v1.0.16

func RunCanary(ctx context.Context, cfg CanaryConfig) CanaryResult

RunCanary executes a canary deploy:

  1. Spins up the canary (green) stack alongside blue.
  2. Health-checks green.
  3. Routes InitialPercent of traffic to green via Nginx weighted upstream.
  4. Monitors green health during the soak window.
  5. On healthy: promotes green to 100% traffic, tears down blue.
  6. On unhealthy: reverts to 0% canary, tears down green, returns error.
  7. Persists state to .nself/state/deploy.json.

type PushSecretsOptions added in v1.1.11

type PushSecretsOptions struct {
	// Target is the deploy target name (e.g. "ops", "staging", "prod").
	Target string

	// EnvFile is the local path to the .env file to push.
	// Defaults to {ProjectRoot}/.env.{Target}, falling back to {ProjectRoot}/.env.
	EnvFile string

	// RemotePath is the remote destination path. Defaults to ~/app/.env.
	RemotePath string

	// DryRun logs what would be done without executing scp.
	DryRun bool

	// ProjectRoot is the local project root used to resolve the default EnvFile.
	// Defaults to the current working directory when empty.
	ProjectRoot string
}

PushSecretsOptions configures the secrets push operation.

type RemoteTarget added in v1.2.1

type RemoteTarget struct {
	// SSHTarget is "user@host" (no path component).
	SSHTarget string
	// RemotePath is the absolute path on the remote host where the nSelf
	// project lives (used only for cd-prefixed commands; empty is fine for
	// a plain `docker exec`, which needs no working directory).
	RemotePath string
	// KeyPath is the SSH private key path.
	KeyPath string
}

RemoteTarget describes a resolved remote host for a non-deploy command.

func ResolveRemoteTargetFromEnv added in v1.2.1

func ResolveRemoteTargetFromEnv(target string) (rt RemoteTarget, ok bool)

ResolveRemoteTargetFromEnv builds a RemoteTarget for "staging"/"prod" from the same NSELF_DEPLOY_HOST_<TARGET> / <TARGET>_DEPLOY_HOST env-var convention used by `nself deploy`. Returns ok=false when no host is configured for target (e.g. "local", or a target with no env var set) — callers should fall back to local execution in that case.

type RollbackConfig

type RollbackConfig struct {
	// Service is the nSelf service to roll back (e.g., "ping_api").
	Service string

	// DeployKey is the deploy authorization key (NSELF_DEPLOY_KEY).
	// Required — no anonymous rollbacks.
	DeployKey string

	// Reason is a human-readable reason for the rollback.
	// Set by the SLO watcher: "slo-watcher: <alert description>"
	Reason string

	// Environment is "prod", "staging", etc. Defaults to "prod".
	Environment string

	// MaxRetries is the maximum number of rollback retry attempts. Default: 1.
	MaxRetries int

	// ProjectRoot is the nSelf project root directory. Used to locate
	// docker-compose.yml and state files.
	ProjectRoot string
}

RollbackConfig holds the parameters for a deploy rollback.

type RollbackResult

type RollbackResult struct {
	// Success is true if the rollback completed without error.
	Success bool

	// Service is the service that was rolled back.
	Service string

	// PriorVersion is the version that was restored.
	PriorVersion string

	// Error is set if rollback failed.
	Error string

	// AuditEventID is the ID written to np_auditlog_events.
	AuditEventID string

	// Duration is how long the rollback took.
	Duration time.Duration

	// UIState is one of the 7 UI states for the rollback.
	UIState RollbackUIState
}

RollbackResult is the outcome of a deploy rollback.

func ExecuteRollback

func ExecuteRollback(ctx context.Context, cfg RollbackConfig) RollbackResult

ExecuteRollback performs a service rollback. It: 1. Validates the deploy key 2. Discovers the prior container image tag 3. Re-deploys the prior image 4. Logs an audit event 5. Returns a RollbackResult with the UI state

type RollbackUIState

type RollbackUIState string

RollbackUIState represents the 7 possible states for rollback UI.

const (
	UIStateLoading     RollbackUIState = "loading"           // rollback in progress
	UIStateEmpty       RollbackUIState = "empty"             // no prior version to roll back to
	UIStateError       RollbackUIState = "error"             // rollback command failed
	UIStatePopulated   RollbackUIState = "populated"         // rollback complete + verified
	UIStateOffline     RollbackUIState = "offline"           // no staging connection
	UIStatePermDenied  RollbackUIState = "permission-denied" // no deploy key
	UIStateRateLimited RollbackUIState = "rate-limited"      // circuit breaker engaged
)

type SSHConfig added in v1.1.1

type SSHConfig struct {
	// Host is the remote target in "user@host:/remote/path" format.
	// NSELF_DEPLOY_HOST is the conventional env var name.
	Host string

	// KeyPath is the path to the SSH private key.
	// Falls back to NSELF_DEPLOY_KEY_PATH, then ~/.ssh/id_ed25519.
	KeyPath string

	// Follow streams container logs after a successful deploy until the
	// context is cancelled (e.g. Ctrl-C from the user).
	Follow bool
}

SSHConfig holds parameters for an SSH-based remote deploy.

func SSHConfigFromEnv added in v1.1.1

func SSHConfigFromEnv(target string) SSHConfig

SSHConfigFromEnv builds an SSHConfig from environment variables. target should be "staging" or "prod".

type Strategy added in v1.0.16

type Strategy string

Strategy is the deploy strategy used.

const (
	StrategyRolling   Strategy = "rolling"
	StrategyBlueGreen Strategy = "blue-green"
	StrategyCanary    Strategy = "canary"
)

type StrategyState added in v1.0.16

type StrategyState struct {
	// SchemaVersion is the version of the StrategyState schema.
	// Set to 1 on all writes. Readers treat 0 (missing field) as the legacy default.
	SchemaVersion int `json:"schema_version"`

	// Strategy is the deploy strategy used.
	Strategy Strategy `json:"strategy"`

	// Target is the deploy target: local, staging, prod.
	Target string `json:"target"`

	// StartedAt is the timestamp when the deploy started.
	StartedAt time.Time `json:"started_at"`

	// CompletedAt is the timestamp when the deploy completed (success or failure).
	CompletedAt time.Time `json:"completed_at"`

	// Success reports whether the deploy succeeded.
	Success bool `json:"success"`

	// CanaryPercent is the final canary traffic split at completion (0 or 100 for non-canary).
	CanaryPercent int `json:"canary_percent"`

	// RolledBack is true when the deploy triggered an automatic rollback.
	RolledBack bool `json:"rolled_back"`

	// Error is the failure reason when Success is false.
	Error string `json:"error,omitempty"`

	// BlueGreenStateFile is the path to the underlying blue/green state file,
	// populated when strategy is blue-green or canary.
	BlueGreenStateFile string `json:"blue_green_state_file,omitempty"`
}

StrategyState records the outcome of the last deploy for a given strategy.

func LoadDeployState added in v1.0.16

func LoadDeployState(projectRoot string) (StrategyState, error)

LoadDeployState reads the deploy state from .nself/state/deploy.json. Returns a zero-value StrategyState when no state file exists (fresh install).

Directories

Path Synopsis
Package bluegreen implements zero-downtime blue/green and canary deploys for the nSelf CLI (B47 + B48).
Package bluegreen implements zero-downtime blue/green and canary deploys for the nSelf CLI (B47 + B48).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL