Reflang — Reference Language
Reflang é a linguagem de substituição declarativa usada nos templates do DeployAlly. Ela permite referenciar valores de diversos contextos (inputs do usuário, secrets, contexto do deploy, metadados do sistema), aplicar funções para gerar ou transformar valores, e fazer indireção via substituição aninhada.
Sintaxe básica: ${namespace.path}. Tudo entre ${...} é resolvido em tempo de deploy.
Namespaces
Cada namespace expõe um contexto diferente:
| Namespace | Contexto | Quando disponível | Exemplo |
|---|---|---|---|
input |
Inputs declarados em inputs.{required,optional,advanced} |
Após o wizard | ${input.WEB_HOSTNAME} |
secrets |
Secrets resolvidos (via provider chain) | Após secrets: ser processado |
${secrets.DB_PASSWORD} |
self |
Campos do próprio template (image, port, etc.) | Sempre | ${self.image} |
instance |
Metadados da instance (uid, slug, namespace) | Sempre | ${instance.uid} |
context |
Contexto do deploy (profile, dry_run, source) | Sempre | ${context.profile} |
tenant |
Tenant ativo (multi-tenant deploys) | Quando há tenant scope | ${tenant.id} |
system |
Atributos do host (memória, CPUs, hostname) | Após preflight | ${system.memory_mb} |
env |
Variáveis de ambiente do host | Sempre | ${env.HOME} |
needs |
Valores expostos por assets satisfeitos via needs |
Após auto-provision | ${needs.main_db.host} |
asset |
Asset compartilhado declarado por classe | Após registry lookup | ${asset.mysql.connection_string} |
Como `needs` e `asset` se relacionam
needsreferencia o asset conforme o consumer declarou na lista de necessidades. Útil quando o template declara várias opções (ex:needs: [{ class: mysql }, { class: postgresql }]) e você quer referenciar o que foi escolhido sem se importar com qual.assetreferencia um asset específico por classe, lookup direto no registry. Útil quando o template assume uma classe específica.
Funções
Funções podem aparecer em qualquer expressão Reflang. Argumentos podem ser strings literais, números ou outras expressões ${...}.
Geradores
| Função | Retorno | Descrição |
|---|---|---|
random.hex(N) |
string | N caracteres hex (0-9a-f) |
random.alnum(N) |
string | N caracteres alfanuméricos (a-zA-Z0-9) |
random.password(N) |
string | N caracteres password-safe |
random.uuid() |
string | UUID v4 |
Exemplo:
secrets:
API_TOKEN: ${random.hex(32)}
ADMIN_PASSWORD: ${random.password(24)}
INSTANCE_ID: ${random.uuid()}Lógica e Controle
| Função | Retorno | Descrição |
|---|---|---|
if(cond, a, b) |
qualquer | Retorna a se cond truthy, senão b |
default(v, fallback) |
qualquer | Retorna v se definido e não vazio, senão fallback |
exists(v) |
bool | true se a expressão resolve para valor não vazio |
Exemplo:
environment:
LOG_LEVEL: ${if(input.DEBUG, "debug", "info")}
DB_HOST: ${default(input.DB_HOST, "localhost")}
HAS_SMTP: ${exists(input.SMTP_HOST)}Strings
| Função | Retorno | Descrição |
|---|---|---|
concat(...) |
string | Concatena os argumentos |
lower(s) |
string | Lowercase |
upper(s) |
string | Uppercase |
replace(s, from, to) |
string | Substitui from por to em s |
Exemplo:
environment:
DB_NAME: ${concat("app_", lower(input.TENANT_SLUG))}
SAFE_HOST: ${replace(input.HOST, ".", "_")}Substituição Aninhada
Reflang resolve referências aninhadas de dentro pra fora. Útil quando o nome do campo depende de outro valor:
environment:
# SLUG_UPPER = "PROD", então acessa input.PROD_DOMAIN
TARGET_DOMAIN: ${input.${SLUG_UPPER}_DOMAIN}O motor resolve ${SLUG_UPPER} primeiro (resultando em, por exemplo, PROD), depois acessa input.PROD_DOMAIN.
Provider Chain em Secrets
Secrets têm uma cadeia de providers tentada em ordem. O primeiro que retorna valor é usado.
secrets:
DB_PASSWORD:
provider: input # tenta input.DB_PASSWORD
fallback:
provider: env # se vazio, tenta env.DB_PASSWORD
fallback:
generate: # último fallback: gera
type: alnum
length: 32Forma simplificada (provider único + generate como fallback automático):
secrets:
DB_PASSWORD:
provider: input
generate:
type: hex
length: 32Tipos de provider:
| Provider | Origem |
|---|---|
input |
Input do template (key implícito = nome do secret) |
env |
Variável de ambiente do host |
generate |
Gera novo valor usando função (hex, alnum, password, uuid) |
asset |
Lê do asset declarado em needs |
Quando o provider tem input ou env sem :KEY, o motor usa o próprio nome do secret como key.
Conditional Environment
Variáveis de ambiente podem ser geradas condicionalmente:
environment:
- name: SMTP_HOST
value: ${input.SMTP_HOST}
when: ${exists(input.SMTP_HOST)}
- name: SMTP_PORT
value: ${default(input.SMTP_PORT, "587")}
when: ${exists(input.SMTP_HOST)}Variáveis cuja expressão when resulta falsa são omitidas do container — não viram strings vazias.
Exemplos Práticos
Template de Application com Banco
species: meu-app
archetype: application
image: meu-org/app:1.0
inputs:
required:
- WEB_HOSTNAME
- ADMIN_EMAIL
advanced:
- DEBUG # default: false
secrets:
DB_PASSWORD:
provider: input
generate:
type: alnum
length: 32
SESSION_KEY:
generate:
type: hex
length: 64
needs:
- class: mysql
options:
- { species: mysql, variant: mysql-8.4, default: true }
- { species: mariadb, variant: latest }
environment:
WEB_HOSTNAME: ${input.WEB_HOSTNAME}
ADMIN_EMAIL: ${input.ADMIN_EMAIL}
DB_HOST: ${needs.main_db.host}
DB_USER: ${needs.main_db.user}
DB_PASSWORD: ${secrets.DB_PASSWORD}
DB_NAME: ${concat("app_", lower(instance.uid))}
SESSION_KEY: ${secrets.SESSION_KEY}
LOG_LEVEL: ${if(input.DEBUG, "debug", "info")}
routes:
- hostname: ${input.WEB_HOSTNAME}
port: 8080Asset com Dispatcher per_instance
species: meu-db
archetype: asset
image: meu-org/db:latest
provides:
asset_class: meu-db
functions:
create-database:
params:
- name: db_name
required: true
- name: db_user
required: true
default: ${concat("user_", lower(input.db_name))}
exec:
command: ["create-db", "${input.db_name}", "${input.db_user}"]
storage:
- kind: volume
name: data
path: /var/lib/dbConfig File via Storage
storage:
- kind: config_file
path: /etc/app/config.yaml
content: |
app:
port: ${self.port}
log_level: ${default(input.LOG_LEVEL, "info")}
database:
host: ${needs.main_db.host}
password: ${secrets.DB_PASSWORD}O motor renderiza o conteúdo (substituição Reflang aplicada), salva em /opt/deployally/<uid>/config/config.yaml e faz bind-mount single file no container.
Referência Rápida
Namespaces
| Namespace | Disponível em |
|---|---|
input |
inputs do wizard |
secrets |
secrets resolvidos |
self |
campos do próprio template |
instance |
metadados da instance |
context |
contexto do deploy |
tenant |
tenant ativo |
system |
recursos do host |
env |
env vars do host |
needs |
assets via needs |
asset |
asset por classe |
Funções
random.hex(N)
random.alnum(N)
random.password(N)
random.uuid()
if(cond, a, b)
default(v, fallback)
exists(v)
concat(...)
lower(s)
upper(s)
replace(s, from, to)Provider Chain (Secrets)
input → env → generate → assetPrimeiro provider com valor não vazio vence.
Navegação
Conceitos Relacionados
- Templates — visão geral do sistema de templates e dos seis archetypes
- Taxonomia — kingdom / family / species
- Manifestos — armazenamento local de configurações resolvidas
- Ecologia — relações entre serviços e auto-provisão
Operação
- Comandos CLI — como deployar usando templates Reflang
- Integração API — uso programático (restrito)