deploy

package
v1.4.5 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package deploy implements `nuzur-cli deploy` / `nuzur-cli destroy`: it provisions a Linux server, self-hosts the project's database on it (localhost-only), runs the generated API, and pairs the box back to nuzur via an outbound local agent — so the database is fully managed in nuzur with no inbound DB ports.

The package is transport-agnostic at its core: every provider runs the same bootstrap over SSH. A Provisioner supplies only the create-VM / firewall / destroy slice; the bring-your-own-server (SSH) provider implements that with no provider API and doubles as the universal path for any Linux host.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DeleteDeployment

func DeleteDeployment(id string) error

DeleteDeployment removes a deployment's state file. Not-found is not an error.

func ProviderResourceName added in v1.2.6

func ProviderResourceName(identifier string) (string, error)

ProviderResourceName mints the provider-side name for a deploy's resources. The deploy command calls this before provisioning so the name can be persisted ahead of the create call; adapters get it via Spec.ResourceName.

func RenderBootstrap

func RenderBootstrap(p BootstrapParams) (string, error)

RenderBootstrap produces the bootstrap shell script for a target.

func RenderTeardown added in v1.1.3

func RenderTeardown(p TeardownParams) (string, error)

RenderTeardown produces the teardown shell script for a target.

func SaveDeployment

func SaveDeployment(d *Deployment) error

SaveDeployment writes (or overwrites) the deployment's state file, 0600.

Types

type AzureProvisioner added in v1.2.5

type AzureProvisioner struct{}

func NewAzureProvisioner added in v1.2.5

func NewAzureProvisioner() *AzureProvisioner

func (*AzureProvisioner) ConfigureFirewall added in v1.2.5

func (p *AzureProvisioner) ConfigureFirewall(ctx context.Context, prov Provisioned, rules []FirewallRule) error

func (*AzureProvisioner) Destroy added in v1.2.5

func (p *AzureProvisioner) Destroy(ctx context.Context, prov Provisioned) error

func (*AzureProvisioner) FindInstanceByName added in v1.2.6

func (p *AzureProvisioner) FindInstanceByName(ctx context.Context, name, region string) (string, error)

FindInstanceByName resolves an Azure resource-group name — which for this adapter IS the instance id (see the file comment). `az group exists` answers true/false without erroring, so this is just that check.

func (*AzureProvisioner) Provision added in v1.2.5

func (p *AzureProvisioner) Provision(ctx context.Context, spec Spec) (Provisioned, error)

type BootstrapParams

type BootstrapParams struct {
	Identifier string
	DBEngine   DBEngine
	DBName     string
	DBUser     string
	// DBOnly provisions only the DB engine (--db) + the paired agent + connection
	// (and applies the schema); it skips the generated app, Docker, and Caddy. The
	// database is then managed entirely through nuzur.
	DBOnly bool
	// ExternalDB means the app/agent connect to a caller-supplied existing DB
	// (--db-dsn, local or remote, MySQL or Postgres) instead of a self-hosted one.
	// The bootstrap skips DB install + DB/user creation + backups; DBHost/
	// DBPort/DBPassword/DBParams/DBDSN carry the connection.
	ExternalDB bool
	DBHost     string
	DBPort     string
	DBPassword string // external only; self-hosted generates its own on the box
	DBParams   string // DSN query params (e.g. parseTime=true / sslmode=require)
	DBDSN      string // external only: the raw DSN used for the agent connection
	// DBSchema is the agent connection's default schema — set for Postgres (a
	// namespace like `public`), empty for MySQL where the database is the schema.
	DBSchema    string
	GRPCEnabled bool
	// JWTAuth means the generated app uses the JWT auth server, which reads its
	// signing key from config (auth.jwt.key). The generated base.yaml ships a
	// placeholder, so the bootstrap generates a real random key into prod.yaml —
	// without it token creation is broken.
	JWTAuth bool
	// Domain, when set, makes Caddy serve HTTPS/443 with an automatic Let's
	// Encrypt cert for this project's site. Empty means IP-only: the project gets
	// its own auto-assigned public port on the host IP (plain HTTP), so multiple
	// projects can coexist without domains.
	Domain string
	// Host is the box IP/hostname the CLI connected to; used to compose the
	// IP-only public URL (http://{host}:{publicPort}) written back for the report.
	Host              string
	InnoDBBufferMB    int
	ProjectDir        string // per-project dir, e.g. /etc/nuzur/{identifier} (holds secrets + url)
	ConfigDir         string // per-project config, e.g. /etc/nuzur/{identifier}/config
	RemoteSrcDir      string // where generated source was copied
	ImageName         string
	ContainerName     string
	ProvisioningToken string
	// ConnUUID/ConnName register the localhost DB as a named agent connection
	// (locally, --no-publish) so the daemon serves it by UUID; the deploy
	// command publishes the catalog to nuzur with the user's token.
	ConnUUID string
	ConnName string
	// CLIInstallCmd optionally overrides how the nuzur CLI is installed on the
	// box. When empty, the bootstrap downloads the matching Linux binary from
	// the nuzur-cli GitHub releases. A custom command must leave the binary at
	// NuzurBin.
	CLIInstallCmd string
	// NuzurBin is the absolute path to the installed nuzur binary (used in the
	// agent systemd unit).
	NuzurBin string
	// S3* configure the generated app's file-upload endpoints (/upload, /sign).
	// Unlike the DB password, these credentials are resolved from the team's
	// ObjectStore (KMS) and passed IN, then written into prod.yaml (0600) — like
	// the external --db-dsn path, the secret does travel through the bootstrap.
	S3Enabled bool
	S3Region  string
	S3Bucket  string
	S3Key     string
	S3Secret  string
}

BootstrapParams are the values rendered into the remote bootstrap script. The DB password is intentionally NOT here — it is generated on the box so the plaintext secret never leaves the server.

type DBEngine

type DBEngine string

DBEngine is the database engine. Both MySQL and Postgres are supported as a self-hosted local tier (installed + provisioned on the box) and as an external (--db-dsn) database the app/agent connect to directly.

const (
	DBMySQL    DBEngine = "mysql"
	DBPostgres DBEngine = "postgres"
)

type Deployment

type Deployment struct {
	ID                 string   `json:"id"`
	Provider           Provider `json:"provider"`
	ProviderInstanceID string   `json:"provider_instance_id,omitempty"` // cloud VM/instance id (for destroy); empty for BYO-SSH
	// ProviderResourceName is the name nuzur minted for the VM, written to disk
	// BEFORE the provider create call. If a deploy dies during that call, the id
	// never comes back and this name is the only handle left on a VM that may be
	// running and billing — destroy resolves it via Provisioner.FindInstanceByName.
	ProviderResourceName string `json:"provider_resource_name,omitempty"`
	// Provisioning marks a deployment whose VM is still being created. It is set
	// before the create call and cleared once the deploy completes, so a record left
	// with it set is a deploy that died in flight and may have leaked a VM.
	Provisioning       bool      `json:"provisioning,omitempty"`
	Region             string    `json:"region,omitempty"` // cloud region the VM lives in
	Host               string    `json:"host"`
	User               string    `json:"user"`
	Port               int       `json:"port"`
	Identifier         string    `json:"identifier"`
	ProjectUUID        string    `json:"project_uuid"`
	ProjectVersionUUID string    `json:"project_version_uuid"`
	LocalAgentUUID     string    `json:"local_agent_uuid"`
	ConnUUID           string    `json:"conn_uuid,omitempty"`
	DBEngine           DBEngine  `json:"db_engine"`
	ExternalDB         bool      `json:"external_db,omitempty"` // --db-dsn: an existing DB, not self-hosted (never dropped on destroy)
	SourceDir          string    `json:"source_dir,omitempty"`  // persistent app-source workspace (reused on re-deploy)
	Domain             string    `json:"domain,omitempty"`      // set when deployed with --domain (HTTPS site)
	APIURL             string    `json:"api_url,omitempty"`     // resolved front-door URL
	PublicURL          string    `json:"public_url,omitempty"`  // same as APIURL; explicit alias
	DataManagerURL     string    `json:"data_manager_url,omitempty"`
	CreatedAt          time.Time `json:"created_at"`
}

Deployment is the persisted record of one `nuzur-cli deploy`, written under ~/.config/nuzur/deployments/<id>.json. It is the source of truth for `nuzur-cli destroy` (revoke the agent, delete provider infra) and `deploy list`.

func ListDeployments

func ListDeployments() ([]Deployment, error)

ListDeployments returns all recorded deployments, newest first.

func LoadDeployment

func LoadDeployment(id string) (*Deployment, error)

LoadDeployment reads a single deployment by id.

type DigitalOceanProvisioner added in v1.2.0

type DigitalOceanProvisioner struct{}

func NewDigitalOceanProvisioner added in v1.2.0

func NewDigitalOceanProvisioner() *DigitalOceanProvisioner

func (*DigitalOceanProvisioner) ConfigureFirewall added in v1.2.0

func (p *DigitalOceanProvisioner) ConfigureFirewall(ctx context.Context, prov Provisioned, rules []FirewallRule) error

func (*DigitalOceanProvisioner) Destroy added in v1.2.0

func (*DigitalOceanProvisioner) FindInstanceByName added in v1.2.6

func (p *DigitalOceanProvisioner) FindInstanceByName(ctx context.Context, name, region string) (string, error)

FindInstanceByName resolves a droplet name to its id. doctl has no name filter (only --tag-name), so this lists and matches; an empty list exits 0, so "not found" is an empty result rather than an error.

func (*DigitalOceanProvisioner) Provision added in v1.2.0

func (p *DigitalOceanProvisioner) Provision(ctx context.Context, spec Spec) (Provisioned, error)

type FirewallRule added in v1.2.0

type FirewallRule struct {
	Port    int
	PortEnd int // inclusive range end; 0 → single port
}

FirewallRule is one inbound-TCP allowance for a cloud provider firewall. A single port sets Port (PortEnd == 0); a contiguous range sets both. These mirror the box's own ufw rules (SSH + the Caddy front doors) as defense in depth — the on-box ufw remains the authoritative gate.

type GCPProvisioner added in v1.2.5

type GCPProvisioner struct{}

func NewGCPProvisioner added in v1.2.5

func NewGCPProvisioner() *GCPProvisioner

func (*GCPProvisioner) ConfigureFirewall added in v1.2.5

func (p *GCPProvisioner) ConfigureFirewall(ctx context.Context, prov Provisioned, rules []FirewallRule) error

func (*GCPProvisioner) Destroy added in v1.2.5

func (p *GCPProvisioner) Destroy(ctx context.Context, prov Provisioned) error

func (*GCPProvisioner) FindInstanceByName added in v1.2.6

func (p *GCPProvisioner) FindInstanceByName(ctx context.Context, name, region string) (string, error)

FindInstanceByName resolves a GCP instance name — which for this adapter IS the instance id (see the file comment) — confirming it exists in the zone. gcloud exits 0 with no output when the filter matches nothing.

func (*GCPProvisioner) Provision added in v1.2.5

func (p *GCPProvisioner) Provision(ctx context.Context, spec Spec) (Provisioned, error)

type HetznerProvisioner added in v1.2.0

type HetznerProvisioner struct{}

func NewHetznerProvisioner added in v1.2.0

func NewHetznerProvisioner() *HetznerProvisioner

func (*HetznerProvisioner) ConfigureFirewall added in v1.2.0

func (p *HetznerProvisioner) ConfigureFirewall(ctx context.Context, prov Provisioned, rules []FirewallRule) error

func (*HetznerProvisioner) Destroy added in v1.2.0

func (p *HetznerProvisioner) Destroy(ctx context.Context, prov Provisioned) error

func (*HetznerProvisioner) FindInstanceByName added in v1.2.6

func (p *HetznerProvisioner) FindInstanceByName(ctx context.Context, name, region string) (string, error)

FindInstanceByName resolves a Hetzner server name to its id. This lists and matches rather than using `server describe <name>`, which exits non-zero with "Server not found" — an expected outcome here, not a failure.

func (*HetznerProvisioner) Provision added in v1.2.0

func (p *HetznerProvisioner) Provision(ctx context.Context, spec Spec) (Provisioned, error)

type InstanceRef added in v1.2.6

type InstanceRef struct {
	InstanceID   string
	Region       string
	Host         string
	ResourceName string
}

InstanceRef is a VM the provider has just acknowledged. It is reported the moment it exists — before it is reachable — so the caller can persist it while the deploy is still in flight. Host may be empty for a provider that assigns the address asynchronously (Vultr); the id and name are always enough to delete it.

type LinodeProvisioner added in v1.2.5

type LinodeProvisioner struct{}

func NewLinodeProvisioner added in v1.2.5

func NewLinodeProvisioner() *LinodeProvisioner

func (*LinodeProvisioner) ConfigureFirewall added in v1.2.5

func (p *LinodeProvisioner) ConfigureFirewall(ctx context.Context, prov Provisioned, rules []FirewallRule) error

func (*LinodeProvisioner) Destroy added in v1.2.5

func (p *LinodeProvisioner) Destroy(ctx context.Context, prov Provisioned) error

func (*LinodeProvisioner) FindInstanceByName added in v1.2.6

func (p *LinodeProvisioner) FindInstanceByName(ctx context.Context, name, region string) (string, error)

FindInstanceByName resolves a linode label to its id. Linode filters server-side on --label and exits 0 with no output when nothing matches, so an empty result is "no such linode", not an error.

func (*LinodeProvisioner) Provision added in v1.2.5

func (p *LinodeProvisioner) Provision(ctx context.Context, spec Spec) (Provisioned, error)

type Provider

type Provider string

Provider identifies how the target server is obtained/managed.

const (
	// ProviderSSH is bring-your-own-server: the user supplies an existing host.
	// It doubles as the universal fallback for any Linux box.
	ProviderSSH Provider = "ssh"
	// Managed providers create the VM for the user by shelling out to the
	// provider's own (already-authenticated) CLI.
	ProviderDigitalOcean Provider = "digitalocean"
	ProviderHetzner      Provider = "hetzner"
	ProviderAWS          Provider = "aws"
	ProviderGCP          Provider = "gcp"
	ProviderAzure        Provider = "azure"
	ProviderVultr        Provider = "vultr"
	ProviderLinode       Provider = "linode"
	ProviderScaleway     Provider = "scaleway"
)

type ProviderConfig added in v1.2.0

type ProviderConfig struct {
	Region     string // provider region/location (e.g. "nyc3", "nbg1")
	Size       string // instance size/type (provider-specific; empty → adapter default)
	Image      string // OS image (empty → adapter default, an Ubuntu LTS)
	SSHKeyName string // name/id of an SSH key already registered with the provider;

}

ProviderConfig holds the managed-provisioning inputs for a cloud provider. Ignored by the BYO-SSH provider. Provider auth is deliberately NOT here — the adapters shell out to the user's already-authenticated provider CLI, so nuzur never handles provider tokens.

type Provisioned added in v1.2.0

type Provisioned struct {
	Target     Target
	InstanceID string // provider VM/instance id
	Region     string // provider region the VM lives in
}

Provisioned is the result of Provision: a reachable Target plus the identifiers a cloud teardown needs. For BYO-SSH, InstanceID/Region are empty (nothing to delete). These are persisted on the Deployment record so `destroy` can find and delete the VM later.

type Provisioner

type Provisioner interface {
	// Provision returns a reachable, SSH-ready Target. BYO-SSH validates and
	// returns the user-supplied host; a cloud provider creates a VM, waits for
	// SSH, and returns its address + instance id.
	Provision(ctx context.Context, spec Spec) (Provisioned, error)
	// ConfigureFirewall restricts inbound to the given TCP rules (SSH + the Caddy
	// front doors). BYO-SSH is a no-op (the box's ufw does it); cloud adapters
	// create a provider security group/firewall for the instance.
	ConfigureFirewall(ctx context.Context, p Provisioned, rules []FirewallRule) error
	// Destroy tears down provider-created infrastructure. BYO-SSH is a no-op
	// (the user owns the box); a cloud provider deletes the VM by instance id.
	Destroy(ctx context.Context, p Provisioned) error
	// FindInstanceByName resolves a provider-side resource name to an instance id,
	// returning "" (and no error) when nothing matches. This is the last-resort
	// recovery path: a deploy killed DURING the create call leaves a VM whose id was
	// never returned to us, and the name — minted and persisted before the call — is
	// then the only handle on it. BYO-SSH returns "" (nothing is ours to find).
	FindInstanceByName(ctx context.Context, name, region string) (string, error)
}

Provisioner is the per-provider seam: everything else (the bootstrap) is shared. For BYO-SSH these are near-trivial; a cloud adapter implements them by shelling out to the provider's CLI.

func NewProvisioner added in v1.2.0

func NewProvisioner(provider Provider) (Provisioner, error)

NewProvisioner returns the adapter for a provider. An empty provider defaults to BYO-SSH.

type SSHProvisioner

type SSHProvisioner struct{}

SSHProvisioner implements Provisioner for a user-supplied host. It performs no provider-API work: the box already exists, the firewall is configured on the box by the bootstrap (ufw), and teardown of the box itself is the user's.

func NewSSHProvisioner

func NewSSHProvisioner() *SSHProvisioner

func (*SSHProvisioner) ConfigureFirewall

func (p *SSHProvisioner) ConfigureFirewall(ctx context.Context, prov Provisioned, rules []FirewallRule) error

ConfigureFirewall is a no-op for BYO-SSH: the firewall (ufw, 443+22 only) is applied on the box as part of the bootstrap. Cloud adapters use this for provider-level security groups.

func (*SSHProvisioner) Destroy

func (p *SSHProvisioner) Destroy(ctx context.Context, prov Provisioned) error

Destroy is a no-op for BYO-SSH: the user owns the box. Agent revocation and local-state cleanup are handled by the destroy command, not the provisioner.

func (*SSHProvisioner) FindInstanceByName added in v1.2.6

func (p *SSHProvisioner) FindInstanceByName(ctx context.Context, name, region string) (string, error)

FindInstanceByName finds nothing for BYO-SSH: nuzur created no instance, so there is never one of ours to recover.

func (*SSHProvisioner) Provision

func (p *SSHProvisioner) Provision(ctx context.Context, spec Spec) (Provisioned, error)

type SSHRunner

type SSHRunner struct {
	Target Target
	// Sudo runs the bootstrap script through `sudo` (for non-root SSH users on
	// hosts with passwordless sudo). The DB copy still lands in a user-writable
	// path, so only the privileged bootstrap needs it.
	Sudo bool
	// Stderr, when set, receives live command stderr (progress). Defaults to
	// os.Stderr.
	Stderr *os.File
}

SSHRunner executes commands and copies files to a Target by shelling out to the system `ssh` / `scp`. This reuses the user's ssh-agent and ~/.ssh/config (matching the "shell out" approach) and avoids in-process key handling.

func NewSSHRunner

func NewSSHRunner(t Target) *SSHRunner

func (*SSHRunner) Capture

func (r *SSHRunner) Capture(ctx context.Context, command string) (string, error)

Capture runs a remote command and returns its stdout (trimmed). Used for health checks and status probes.

func (*SSHRunner) CopyDir

func (r *SSHRunner) CopyDir(ctx context.Context, localDir, remotePath string) error

CopyDir copies localDir's CONTENTS to remotePath on the host, by streaming a gzipped tar over ssh.

This used to be `scp -r`, which transfers each file in its own SFTP round-trip. A generated app is ~650 small source files, so the copy was latency-bound rather than bandwidth-bound — on a transatlantic link it crawled at a few KB/s and took many minutes to move ~4MB. One tar stream is a single round-trip, and Go source gzips ~5-10x, so the same payload ships in seconds.

`tar -C localDir .` (contents, not the directory itself) matches the old scp -r semantics: the caller passes a non-existent remotePath and expects it to become a copy of localDir.

func (*SSHRunner) Ping

func (r *SSHRunner) Ping(ctx context.Context) error

Ping verifies the host is reachable and key auth works.

func (*SSHRunner) RunCommand

func (r *SSHRunner) RunCommand(ctx context.Context, command string) error

RunCommand runs a single remote command, streaming its output to stderr.

func (*SSHRunner) RunScript

func (r *SSHRunner) RunScript(ctx context.Context, script string) error

RunScript pipes a script to `bash -s` (or `sudo bash -s`) on the remote host. The script runs with `set -euo pipefail` semantics if it declares them itself.

type ScalewayProvisioner added in v1.2.5

type ScalewayProvisioner struct{}

func NewScalewayProvisioner added in v1.2.5

func NewScalewayProvisioner() *ScalewayProvisioner

func (*ScalewayProvisioner) ConfigureFirewall added in v1.2.5

func (p *ScalewayProvisioner) ConfigureFirewall(ctx context.Context, prov Provisioned, rules []FirewallRule) error

func (*ScalewayProvisioner) Destroy added in v1.2.5

func (p *ScalewayProvisioner) Destroy(ctx context.Context, prov Provisioned) error

func (*ScalewayProvisioner) FindInstanceByName added in v1.2.6

func (p *ScalewayProvisioner) FindInstanceByName(ctx context.Context, name, region string) (string, error)

FindInstanceByName resolves a Scaleway server name to its id. `name=` is a PREFIX filter server-side ("server1" also matches "server100"), so the exact match has to happen here — deleting a VM whose name merely starts with ours would be destroying someone else's box.

func (*ScalewayProvisioner) Provision added in v1.2.5

func (p *ScalewayProvisioner) Provision(ctx context.Context, spec Spec) (Provisioned, error)

type Spec

type Spec struct {
	Provider           Provider
	Target             Target
	ProviderConfig     ProviderConfig // managed-provisioning inputs (cloud providers only)
	Identifier         string         // app identifier (image/service name, DB name)
	ProjectUUID        string
	ProjectVersionUUID string
	DBEngine           DBEngine
	// ProvisioningToken is minted by the caller (product IssueProvisioningToken)
	// and placed on the box for headless agent pairing.
	ProvisioningToken string
	// SourceDir is the local directory of generated app source (from the
	// go-code-gen extension) that gets copied to the box and built there.
	SourceDir string
	// ResourceName is the provider-side name for everything this deploy creates.
	// The CALLER mints it (providerResourceName) rather than the adapter, so it can
	// be written to local state BEFORE the create call: a VM whose id we never
	// learned is still findable — and so deletable — by name. Adapters given an
	// empty value mint their own, so direct and test callers still work.
	ResourceName string
	// OnInstanceCreated, when set, is called by a managed provisioner the instant the
	// provider acknowledges the VM — BEFORE waiting for it to become reachable, which
	// takes minutes. That wait is the bulk of the window in which a killed deploy
	// would otherwise strand a running, billing VM that nothing on disk knows about,
	// so this is what makes the VM recoverable. Implementations must be quick and
	// must not error the deploy.
	OnInstanceCreated func(InstanceRef)
}

Spec is the fully-resolved input to a deployment.

type Target

type Target struct {
	Host string // IP or hostname
	User string // SSH user (e.g. root)
	Port int    // SSH port (default 22)
	// KeyPath is an optional explicit private key; empty uses the ssh-agent /
	// ~/.ssh/config resolution.
	KeyPath string
}

Target is a resolved server the bootstrap runs against.

type TeardownParams added in v1.1.3

type TeardownParams struct {
	Identifier    string
	ContainerName string
	ImageName     string
	ProjectDir    string // /etc/nuzur/{identifier}
	DBEngine      DBEngine
	DBName        string
	DBUser        string
	ConnUUID      string // this project's agent connection to remove from the shared agent
	NuzurBin      string
	Purge         bool
	// IsLastProject: this is the only project left on the box, so also remove the
	// shared agent (nuzur-agent.service + pairing creds) and the main Caddyfile.
	// When false, the shared agent is kept for the surviving projects.
	IsLastProject bool
}

TeardownParams are the values rendered into the remote teardown script. It removes THIS project's artifacts (its systemd unit, container, image, its /etc/nuzur/{id} config+secrets, its Caddy site snippet, its backup cron, and its agent connection). The shared agent, MySQL, and packages are left intact unless IsLastProject is set. The database is dropped only when Purge is set.

type VultrProvisioner added in v1.2.5

type VultrProvisioner struct{}

func NewVultrProvisioner added in v1.2.5

func NewVultrProvisioner() *VultrProvisioner

func (*VultrProvisioner) ConfigureFirewall added in v1.2.5

func (p *VultrProvisioner) ConfigureFirewall(ctx context.Context, prov Provisioned, rules []FirewallRule) error

func (*VultrProvisioner) Destroy added in v1.2.5

func (p *VultrProvisioner) Destroy(ctx context.Context, prov Provisioned) error

func (*VultrProvisioner) FindInstanceByName added in v1.2.6

func (p *VultrProvisioner) FindInstanceByName(ctx context.Context, name, region string) (string, error)

FindInstanceByName resolves a Vultr label to its instance id. Vultr has no server-side label filter, so this lists and matches.

func (*VultrProvisioner) Provision added in v1.2.5

func (p *VultrProvisioner) Provision(ctx context.Context, spec Spec) (Provisioned, error)

Jump to

Keyboard shortcuts

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