Documentation
¶
Overview ¶
Package platformimport reads apps from another self-hosted platform (read-only) into a neutral model and maps it to this platform's resources. The source credential is used in memory only.
Index ¶
- Constants
- Variables
- func LooksSecret(key string) bool
- func NormalizeSchedule(s string) string
- func ParseDBVersions(raw string) (map[string]string, error)
- func SanitizeJobName(s string) string
- func SanitizeName(s string) string
- func ValidateVercelTeam(s string) (string, error)
- type APIError
- type App
- type AppPlan
- type Applier
- type BackupSchedule
- type CapRoverSource
- type ClientOptions
- type ComposeSource
- type CoolifySource
- type Cron
- type CronPlan
- type Database
- type DatabasePlan
- type Discovery
- type DockerSSHSource
- type DockerSource
- type DokkuEnvSource
- type DokploySource
- type EmitApp
- type EmitConnection
- type EmitDatabase
- type EmitFile
- type EmitInput
- type EmitJob
- type EmitOptions
- type EmitSecret
- type Env
- type HealthCheck
- type HealthPlan
- type HerokuSource
- type InspectReader
- type Item
- type NetworkPolicy
- type Note
- type Plan
- type PlanOptions
- type Platform
- type RenderSource
- type Report
- type Server
- type Source
- type SourceKind
- type Unsupported
- type VercelSource
- type Volume
- type VolumePlan
Constants ¶
const ( EmitStackFile = "stack.yaml" EmitProjectFile = "project.yaml" EmitDatabasesFile = "databases.yaml" EmitAppsFile = "apps.yaml" EmitDomainsFile = "domains.yaml" EmitSecretsFile = "SECRETS.md" EmitNotesFile = "MIGRATION.md" )
Emitted file names, stable so a migration PR diffs cleanly.
const ( AllowPrivateEnv = "APP_IMPORT_ALLOW_PRIVATE_NETWORKS" AllowLoopbackEnv = "APP_IMPORT_ALLOW_LOOPBACK" )
Environment variables that must be set before a request may opt in to private or loopback source addresses. Both the env var and the request field are required, so a leaked API token alone cannot aim the control plane at the internal network.
const ( LabelSourceID = "import/source-id" LabelSourcePlatform = "import/source-platform" LabelSourceName = "import/source-name" // LabelSession ties a staged app to the guided import session that created it. LabelSession = "import/session" )
Labels stamped on every imported resource. The source-id label is what makes a re-run idempotent and lets an operator find imports to delete.
const ( StatusMapped = "mapped" StatusNeedsAttention = "needs-attention" StatusUnsupported = "unsupported" StatusAlready = "already-imported" StatusSkipped = "skipped" StatusCreated = "created" StatusFailed = "failed" )
Item statuses in a Report.
const ( CollisionSuffix = "suffix" CollisionSkip = "skip" )
Collision modes for a target name that is already taken.
const ConnectionHint = "database connection string, created empty here: set it after the database exists, or run databases link"
ConnectionHint is the SECRETS.md note for a variable that carries a database connection string.
const DataNote = "" /* 171-byte string literal not displayed */
DataNote is added to every report that contains databases.
const DefaultHerokuURL = "https://api.heroku.com"
DefaultHerokuURL is the public Heroku Platform API.
const DefaultRenderURL = "https://api.render.com/v1"
DefaultRenderURL is the public Render REST API.
const DefaultVercelURL = "https://api.vercel.com"
DefaultVercelURL is the public Vercel REST API.
const (
// MaxPages bounds every paginated or fan-out walk.
MaxPages = 200
)
Variables ¶
var ErrBlockedAddress = errors.New("platformimport: source address is not allowed")
ErrBlockedAddress is returned when the source URL resolves to an address the network policy forbids.
Functions ¶
func LooksSecret ¶
LooksSecret reports whether an env var name suggests a secret value.
func NormalizeSchedule ¶
NormalizeSchedule expands the named frequencies a source accepts into a cron expression.
func ParseDBVersions ¶
ParseDBVersions reads "postgres=16,redis=7" into an engine to version map.
func SanitizeJobName ¶
SanitizeJobName turns a source task name into a valid scheduled job name.
func SanitizeName ¶
SanitizeName turns a source name into a valid resource name.
func ValidateVercelTeam ¶
ValidateVercelTeam trims and checks a team id or slug before it reaches a query string.
Types ¶
type App ¶
type App struct {
SourceID string
Name string
Project string
Environment string
// Server names the source host the app runs on, empty when unreported.
Server string
// BuildPack is the source's own build method name, unmapped.
BuildPack string
// PrivateRepo is true when the source needs credentials to clone.
PrivateRepo bool
Kind SourceKind
Image string
// ImageID is the source host's local image ID, set by snapshot sources.
ImageID string
// SourceContainer is the running container's ID on the source host, set by live Docker sources.
SourceContainer string
// HostBuilt marks an image built on the source host and absent from any registry.
HostBuilt bool
GitURL string
GitBranch string
BuildMethod string
BuildPath string
Port int
Env []Env
Domains []string
Volumes []Volume
Replicas int
Health *HealthCheck
Crons []Cron
MemoryBytes int64
NanoCPUs int64
Notes []Note
}
App is one application in the neutral model.
type AppPlan ¶
type AppPlan struct {
SourceID string `json:"source_id"`
SourceName string `json:"source_name"`
Name string `json:"name"`
Image string `json:"image"`
Port int `json:"port"`
Env map[string]string `json:"env,omitempty"`
Secrets map[string]string `json:"-"`
Domains []string `json:"domains,omitempty"`
Volumes []VolumePlan `json:"volumes,omitempty"`
Replicas int `json:"replicas"`
Health *HealthPlan `json:"health,omitempty"`
MemoryBytes int64 `json:"memory_bytes,omitempty"`
NanoCPUs int64 `json:"nano_cpus,omitempty"`
Labels map[string]string `json:"labels"`
Project string `json:"project,omitempty"`
GitURL string `json:"git_url,omitempty"`
GitBranch string `json:"git_branch,omitempty"`
BuildMethod string `json:"build_method,omitempty"`
BuildPath string `json:"build_path,omitempty"`
Crons []CronPlan `json:"crons,omitempty"`
// UnreadSecrets names secret variables the source would not reveal.
UnreadSecrets []string `json:"-"`
}
AppPlan is one app create request. Secrets holds plaintext and is never serialized.
type Applier ¶
type Applier interface {
CreateApp(ctx context.Context, p AppPlan) (warnings []string, err error)
CreateDatabase(ctx context.Context, p DatabasePlan) (warnings []string, err error)
}
Applier creates resources on this platform. Implementations must be safe to call again after a partial failure.
type BackupSchedule ¶
type BackupSchedule struct {
Schedule string
Enabled bool
// Remote is true when the source also uploads the backup to S3.
Remote bool
}
BackupSchedule is one scheduled database backup on the source.
type CapRoverSource ¶
type CapRoverSource struct {
// contains filtered or unexported fields
}
CapRoverSource reads a CapRover instance. The login POST is the only non-GET call it makes.
func NewCapRover ¶
func NewCapRover(baseURL, password string, o ClientOptions) (*CapRoverSource, error)
NewCapRover builds a CapRover source. The password is exchanged for a session token in memory and never stored.
type ClientOptions ¶
type ClientOptions struct {
Policy NetworkPolicy
Insecure bool
// Team scopes a Vercel source to one team id or slug, other platforms reject it.
Team string
}
ClientOptions configure the source HTTP client.
type ComposeSource ¶
type ComposeSource struct {
Data []byte
}
ComposeSource maps a plain compose file, one app per service.
type CoolifySource ¶
type CoolifySource struct {
// contains filtered or unexported fields
}
CoolifySource reads a Coolify instance through its bearer-token API v1.
func NewCoolify ¶
func NewCoolify(baseURL, token string, o ClientOptions) (*CoolifySource, error)
NewCoolify builds a Coolify source. The token is kept in memory only.
type CronPlan ¶
type CronPlan struct {
Name string `json:"name"`
Schedule string `json:"schedule"`
Command string `json:"command"`
}
CronPlan is a scheduled command that becomes a scheduled job on the new app.
type Database ¶
type Database struct {
SourceID string
Name string
Project string
Engine string
Version string
// Environment and InternalHost are set by sources that give each
// database an in-network hostname apps connect to.
Environment string
InternalHost string
// Server, User, DBName, Public and PublicPort describe how the source
// exposes the database. No credential is ever read here.
Server string
User string
DBName string
Public bool
PublicPort int
Backups []BackupSchedule
}
Database is a managed database in the source platform.
type DatabasePlan ¶
type DatabasePlan struct {
SourceID string `json:"source_id"`
SourceName string `json:"source_name"`
Name string `json:"name"`
Engine string `json:"engine"`
Version string `json:"version"`
Project string `json:"project,omitempty"`
}
DatabasePlan is one managed database create request (empty, no data).
type Discovery ¶
type Discovery struct {
Platform Platform
Projects []string
Apps []App
Databases []Database
Unsupported []Unsupported
Servers []Server
// Warnings are source reads that failed softly, so the plan lacks that detail.
Warnings []string
}
Discovery is everything read from a source.
type DockerSSHSource ¶
type DockerSSHSource struct {
Reader InspectReader
}
DockerSSHSource reads a host's containers through a read-only Docker socket tunnel and maps them like a pasted docker inspect snapshot. Env comes from each container's runtime config; the old platform's own stored config (Coolify's database, CapRover's /captain/data, Dokku's /home/dokku) is not read.
type DockerSource ¶
type DockerSource struct {
Data []byte
}
DockerSource maps a `docker inspect` snapshot of every container on a host into the neutral model. It is read-only and needs no credential for the platform that launched the containers, so it works when only the Docker host is reachable (no Coolify token, no Dokploy key).
type DokkuEnvSource ¶
DokkuEnvSource maps one Dokku app from a `dokku config:export` style dump (KEY=VALUE lines). It never contacts a Dokku host.
type DokploySource ¶
type DokploySource struct {
// contains filtered or unexported fields
}
DokploySource reads a Dokploy instance through its x-api-key API.
func NewDokploy ¶
func NewDokploy(baseURL, apiKey string, o ClientOptions) (*DokploySource, error)
NewDokploy builds a Dokploy source. The API key is kept in memory only.
type EmitApp ¶
type EmitApp struct {
Name string
// Image is the prebuilt image. Empty means use EmitOptions.ImageRepo.
Image string
Port int
Replicas int
Env map[string]string
Secrets []EmitSecret
Domains []string
MemoryBytes int64
// Memory is a ready "512Mi" string and wins over MemoryBytes.
Memory string
NanoCPUs int64
HealthPath string
Command []string
PreDeploy string
PostDeploy string
// Connections maps an env var to the emitted database it reads from.
Connections map[string]EmitConnection
Jobs []EmitJob
// Notes are follow-ups for MIGRATION.md that the documents cannot express.
Notes []string
}
EmitApp is one app to write as a kind: App document.
type EmitConnection ¶
EmitConnection is a { from: { database, field } } env reference.
type EmitDatabase ¶
EmitDatabase is one kind: Database document.
type EmitInput ¶
type EmitInput struct {
// Source names where the data came from, for the checklist header.
Source string
Apps []EmitApp
Databases []EmitDatabase
// Notes are source-wide follow-ups for MIGRATION.md.
Notes []string
}
EmitInput is everything an emit needs, from any source adapter.
type EmitJob ¶
type EmitJob struct {
Name string
Schedule string
Command []string
// Mode is "exec" to run in the app's running container; empty means a fresh one.
Mode string
Timezone string
}
EmitJob is one scheduled job of an App document.
type EmitOptions ¶
type EmitOptions struct {
Stack string
Project string
Environment string
// ImageRepo prefixes the image of an app that has none, as REPO/APP:latest.
ImageRepo string
}
EmitOptions name the stack and fill what the source does not know.
type EmitSecret ¶
EmitSecret is a secret the emitted documents reference by name. The value is never held here.
type Env ¶
type Env struct {
Key string
Value string
Secret bool
// BuildTime marks a variable the source only exposes during the image build.
BuildTime bool
}
Env is one environment variable. Secret is true when the source marked it secret or the key looks like one.
type HealthCheck ¶
HealthCheck is an HTTP probe.
type HealthPlan ¶
HealthPlan is an HTTP readiness probe.
type HerokuSource ¶
type HerokuSource struct {
// contains filtered or unexported fields
}
HerokuSource reads a Heroku account through the Platform API, GET only.
func NewHeroku ¶
func NewHeroku(baseURL, token string, o ClientOptions) (*HerokuSource, error)
NewHeroku builds a Heroku source. The API token is kept in memory only. An empty baseURL means the public API.
type InspectReader ¶
InspectReader returns the inspect JSON of every container on a host as one array.
type Item ¶
type Item struct {
Kind string `json:"kind"`
SourceID string `json:"source_id"`
SourceName string `json:"source_name"`
Target string `json:"target,omitempty"`
Status string `json:"status"`
Reasons []string `json:"reasons,omitempty"`
Manual []string `json:"manual,omitempty"`
}
Item is one report row.
type NetworkPolicy ¶
NetworkPolicy decides which destinations the source client may dial. Cloud metadata and link-local addresses are never allowed.
type Note ¶
type Note struct {
// Area groups notes in the exit report, such as "webhook" or "command". Empty means general.
Area string
Reason string
Manual string
}
Note is a per-item caveat found while reading the source.
type Plan ¶
type Plan struct {
Apps []AppPlan
Databases []DatabasePlan
Report Report
}
Plan is the mapped result of a Discovery.
func BuildPlan ¶
func BuildPlan(d *Discovery, o PlanOptions) *Plan
BuildPlan maps a Discovery onto create requests and a Report.
type PlanOptions ¶
type PlanOptions struct {
// Only restricts the plan to these source ids or source names. Empty means all.
Only []string
// Collision is CollisionSuffix (default) or CollisionSkip.
Collision string
// ExistingApps maps an import label value (platform:sourceID) to the
// app already created for it. TakenApps is every app name in use.
ExistingApps map[string]string
TakenApps map[string]bool
// ExistingDatabases maps a database name to "engine:version".
ExistingDatabases map[string]string
// DBVersions is the engine version the user chose per engine, and
// LatestDBVersions the newest catalog version per engine. Both fill in
// databases whose source reports no version.
DBVersions map[string]string
LatestDBVersions map[string]string
}
PlanOptions steer mapping.
type Platform ¶
type Platform string
Platform identifies a supported source.
const ( Coolify Platform = "coolify" Dokploy Platform = "dokploy" CapRover Platform = "caprover" Heroku Platform = "heroku" Vercel Platform = "vercel" Render Platform = "render" Compose Platform = "compose" Dokku Platform = "dokku" // Docker is a docker inspect snapshot of one host, no platform API. Docker Platform = "docker" // DockerSSH reads one host's Docker socket through an SSH login, no platform API. DockerSSH Platform = "docker-ssh" )
Supported source platforms.
func ParsePlatform ¶
ParsePlatform validates a platform name: a live source or a pasted file.
type RenderSource ¶
type RenderSource struct {
// contains filtered or unexported fields
}
RenderSource reads a Render workspace through the REST API, GET only.
func NewRender ¶
func NewRender(baseURL, token string, o ClientOptions) (*RenderSource, error)
NewRender builds a Render source. The API key is kept in memory only. An empty baseURL means the public API.
type Report ¶
type Report struct {
Platform Platform `json:"platform"`
Items []Item `json:"items"`
Counts map[string]int `json:"counts"`
Notes []string `json:"notes,omitempty"`
}
Report is the per-item outcome of a discover, plan or apply.
type Server ¶
type Server struct {
Name string
Address string
// Proxy names the reverse proxy the source runs there, empty when none.
Proxy string
// BuildServer is true when the source uses the host only to build images.
BuildServer bool
Reachable bool
}
Server is a host the source platform deploys to.
type SourceKind ¶
type SourceKind string
SourceKind says where an app's code comes from.
const ( SourceImage SourceKind = "image" SourceGit SourceKind = "git" SourceUnknown SourceKind = "unknown" )
Where an app comes from.
type Unsupported ¶
type Unsupported struct {
Kind string
SourceID string
Name string
Reason string
Manual string
// Context the source reported about the unsupported item, for display.
Project string
Environment string
Server string
Source string
Domains []string
Port int
}
Unsupported is something that cannot be imported.
type VercelSource ¶
type VercelSource struct {
// TeamID scopes every call to a team, empty means the token's personal account.
TeamID string
// contains filtered or unexported fields
}
VercelSource reads a Vercel account or team through the REST API, GET only.
func NewVercel ¶
func NewVercel(baseURL, token string, o ClientOptions) (*VercelSource, error)
NewVercel builds a Vercel source. The API token is kept in memory only. An empty baseURL means the public API.
func (*VercelSource) Discover ¶
func (s *VercelSource) Discover(ctx context.Context) (*Discovery, error)
Discover lists projects, then reads env keys and domains for each.
func (*VercelSource) WithTeam ¶
func (s *VercelSource) WithTeam(id string) *VercelSource
WithTeam scopes the source to one team id (team_...).
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package fakecoolify is a read-only stand-in for the Coolify v4 REST API, shaped from the documented responses the importer consumes.
|
Package fakecoolify is a read-only stand-in for the Coolify v4 REST API, shaped from the documented responses the importer consumes. |
|
cmd/fakecoolify
command
Command fakecoolify serves the read-only fake Coolify API for local runs of the app import flow.
|
Command fakecoolify serves the read-only fake Coolify API for local runs of the app import flow. |
|
Package fakeheroku is a read-only stand-in for the Heroku Platform API, shaped from the documented responses the importer consumes.
|
Package fakeheroku is a read-only stand-in for the Heroku Platform API, shaped from the documented responses the importer consumes. |
|
Package fakerender is a read-only stand-in for the Render REST API, shaped from the documented responses the importer consumes.
|
Package fakerender is a read-only stand-in for the Render REST API, shaped from the documented responses the importer consumes. |
|
Package fakevercel is a read-only stand-in for the Vercel REST API, shaped from the documented responses the importer consumes.
|
Package fakevercel is a read-only stand-in for the Vercel REST API, shaped from the documented responses the importer consumes. |