Skip to content

Cloud-Init Deployment Reference

Reference documentation for deploying plexd on virtual machines using Cloud-Init. Covers the IMDS provider, metadata-related configuration fields, cloud-init templates, and Terraform examples.

IMDSProvider

IMDSProvider implements the MetadataProvider interface by reading a bootstrap token from a cloud instance metadata service (IMDS) over HTTP. It supports IMDSv2 (session-based) with automatic fallback to IMDSv1.

go
type IMDSProvider struct {
    baseURL   string
    tokenPath string
    client    *http.Client
}

Constructor

go
func NewIMDSProvider(timeout time.Duration, baseURL string) *IMDSProvider
ParameterTypeDescription
timeouttime.DurationHTTP client timeout
baseURLstringIMDS base URL (trailing slashes stripped)

ReadValue

go
func (p *IMDSProvider) ReadValue(ctx context.Context, path string) (string, error)

Fetches {baseURL}{path} via HTTP GET. Before the GET, attempts IMDSv2 session token acquisition via PUT to /latest/api/token. If IMDSv2 is unavailable, falls back to unauthenticated IMDSv1 GET.

Request behavior:

  • IMDSv2 session: PUT {baseURL}/latest/api/token with X-aws-ec2-metadata-token-ttl-seconds: 21600. The token is cached and reused across reads until it approaches expiry, so resolving several inputs costs one PUT rather than one per value. Failed acquisitions are not cached, preserving the IMDSv1 fallback
  • Method: GET
  • URL: baseURL + path
  • Auth: X-aws-ec2-metadata-token: {sessionToken} (omitted if IMDSv2 session acquisition failed)
  • Timeout: cfg.MetadataTimeout (HTTP client timeout)
  • Body limit: 4097 bytes (maxValueLength + 1) — reads one byte beyond the limit and rejects anything longer, so an oversized response fails instead of being silently truncated
  • Context: request is context-aware and cancellable

Error conditions:

ConditionError message
Request creationregistration: imds: create request: {err}
HTTP failureregistration: imds: request failed: {err}
404 statusErrMetadataNotFound (sentinel: "not provisioned")
Other non-200 statusregistration: imds: unexpected status {code}
Body read failureregistration: imds: read body: {err}
Oversized responseregistration: imds: value exceeds maximum length of {n} bytes
Empty responseregistration: imds: empty value

Config fields (metadata)

These fields were added to registration.Config for IMDS support:

FieldTypeDefaultDescription
UseMetadataboolfalseEnable cloud metadata token source
MetadataTokenPathstring/plexd/bootstrap-tokenMetadata key path for the bootstrap token
MetadataTimeouttime.Duration2sMaximum time to wait for metadata service response

ApplyDefaults() sets MetadataTokenPath and MetadataTimeout when zero-valued. UseMetadata defaults to false and must be explicitly enabled.

Token resolution with IMDS

When UseMetadata is true, the metadata source is checked as the fourth priority. The plexd up and plexd join commands attach an IMDSProvider automatically, so setting use_metadata: true in the config is all an image needs; the constructor below is for embedding the package directly.

  1. Direct value (Config.TokenValue)
  2. File (Config.TokenFile)
  3. Environment variable (Config.TokenEnv)
  4. Metadata service (MetadataProvider.ReadValue at Config.MetadataTokenPath)

If the metadata service returns an error, the resolver falls through to the "no token found" error. Metadata errors are not propagated — they are treated as "source unavailable."

go
cfg := &registration.Config{
    DataDir:           "/var/lib/plexd",
    UseMetadata:       true,
    MetadataTokenPath: "/plexd/bootstrap-token",
    MetadataTimeout:   2 * time.Second,
}
cfg.ApplyDefaults()

provider := registration.NewIMDSProvider(cfg.MetadataTimeout, "http://169.254.169.254")
resolver := registration.NewTokenResolver(cfg, provider)
result, err := resolver.Resolve(ctx)

Cloud-Init templates

user-data.yaml (full)

Location: deploy/cloud-init/user-data.yaml

Full cloud-init template that writes configuration files and installs plexd.

Template variables:

VariableRequiredDefaultDescription
PLEXD_API_URLyesControl plane API URL
PLEXD_BOOTSTRAP_TOKENyesBootstrap token for enrollment
PLEXD_VERSIONnolatestplexd version to install
PLEXD_HOSTNAMEnoHostname override
PLEXD_LOG_LEVELnoinfoLog level

Actions performed:

  1. package_update: true — updates package lists
  2. Writes /etc/plexd/config.yaml (0600) — full configuration with use_metadata: true
  3. Writes /etc/plexd/bootstrap-token (0600) — bootstrap token
  4. Runs install.sh with --token, --api-url, --version

user-data-minimal.yaml

Location: deploy/cloud-init/user-data-minimal.yaml

Minimal template that only writes the bootstrap token file. No runcmd — assumes plexd is pre-installed.

Template variables:

VariableRequiredDescription
PLEXD_BOOTSTRAP_TOKENyesBootstrap token for enrollment

Actions performed:

  1. Writes /etc/plexd/bootstrap-token (0600) — bootstrap token

Terraform examples

AWS EC2

Location: deploy/cloud-init/examples/terraform-aws.tf

Provisions an AWS EC2 instance with plexd enrollment via cloudinit_config data source.

VariableTypeDefaultDescription
plexd_api_urlstringControl plane API URL
plexd_bootstrap_tokenstringBootstrap token (sensitive)
plexd_versionstringlatestplexd version
instance_typestringt3.microEC2 instance type
ami_idstringAMI ID (must support cloud-init)
subnet_idstringSubnet ID
key_namestring""SSH key pair name (optional)

Security: Enforces IMDSv2 (http_tokens = "required").

OpenStack

Location: deploy/cloud-init/examples/terraform-openstack.tf

Provisions an OpenStack compute instance with plexd enrollment.

VariableTypeDefaultDescription
plexd_api_urlstringControl plane API URL
plexd_bootstrap_tokenstringBootstrap token (sensitive)
plexd_versionstringlatestplexd version
flavor_namestringm1.smallOpenStack flavor
image_namestringImage name (must support cloud-init)
network_namestringNetwork name
key_pairstring""SSH key pair name (optional)

Cloud provider IMDS endpoints

Reference table for common cloud provider IMDS base URLs:

ProviderBase URLAuth mechanism
AWShttp://169.254.169.254IMDSv2 session token (automatic)
GCPhttp://metadata.google.internal/computeMetadata/v1Metadata-Flavor: Google header
Azurehttp://169.254.169.254/metadata/instanceMetadata: true header
OpenStackhttp://169.254.169.254/openstack/latest/meta_data.jsonNone
DigitalOceanhttp://169.254.169.254/metadata/v1None

See also