Skip to content

EKS modules: rvn-eks composite, selectable add-ons, services, and observability - #114

Open
mabadir wants to merge 55 commits into
mainfrom
mabadir/eks-observability
Open

EKS modules: rvn-eks composite, selectable add-ons, services, and observability#114
mabadir wants to merge 55 commits into
mainfrom
mabadir/eks-observability

Conversation

@mabadir

@mabadir mabadir commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

The module-side half of EKS deployment support (pairs with ravionhq/flightcontrol#6973).

Cluster and add-ons

  • compute/eks composite with the rvn-eks module definition
  • Selectable add-ons stack (compute/eks/addons): Karpenter (controller + default node pool), EBS CSI, AWS Load Balancer Controller (installed automatically with any shared load balancer), shared load balancers
  • Runner authenticates to the cluster via EKS access entries: self-registered Terraform runner entry plus an assumable Ravion Runner role with cluster-admin; orphaned Helm releases adopted via upgrade_install
  • Ravion Beacon agent shipped through the add-ons chart, defaulting to the public a8z1i1r2 registry (rvn-eks-addons 0.6.1)

Services

  • EKS service modules with container image builds

Observability

  • Workload metrics: Amazon Managed Prometheus + OTel collector + Grafana role in rvn-eks-addons
  • Logs: in-cluster Loki on S3 (replacing Container Insights), covered in tests, docs, and the module definition
  • UI wiring: workload and cluster metrics to AMP, logs to Loki

Greptile Summary

The PR adds a composite EKS platform, selectable cluster add-ons, AWS-side EKS workload infrastructure, reusable Helm charts, observability integrations, module definitions, and integration tests.

  • Provisions EKS clusters, node capacity, runner access, and optional Karpenter, storage, load-balancing, secrets, metrics, logs, and Beacon components.
  • Adds web, worker, and cron workload definitions with image builds and Helm deployments.
  • Adds shared ALB target-group routing and chart-based Kubernetes workload resources.
  • Adds chart CI and AWS/Terraform test coverage.

Confidence Score: 4/5

The target-group naming collision should be fixed before merging because two valid web workload names can make infrastructure creation fail.

Load-balanced workloads whose names share the retained 24-character prefix resolve to the same account-and-region target group name, while the workflow action pinning issue is independently non-blocking.

Files Needing Attention: compute/eks_service/locals.tf and .github/workflows/helm-charts.yml

Security Review

The new Helm workflow uses mutable action tags. Its permissions are limited to repository read access, but pinning these actions to full commit SHAs would prevent upstream tag movement from changing executed CI code.

Important Files Changed

Filename Overview
compute/eks_service/locals.tf Enables optional load balancing and derives target group names, but truncation can collide for workloads sharing a long prefix.
compute/eks_service/target_group.tf Creates an IP-mode target group consumed by the chart's TargetGroupBinding.
compute/eks/addons/beacon.tf Provisions Beacon credentials and deployment configuration; no changed-code blocking defect was established.
charts/rvn-eks-web/templates/targetgroupbinding.yaml Renders one TargetGroupBinding per supplied target group ARN for pod-IP registration.
.github/workflows/helm-charts.yml Adds chart lint/template CI with minimal permissions, but its action dependencies are referenced through mutable tags.
compute/eks/eks_cluster.tf Composes the cluster module and forwards networking, authentication, encryption, add-on, and Pod Identity settings.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Definition["Ravion EKS module definitions"] --> Cluster["compute/eks composite"]
  Cluster --> EKS["EKS control plane"]
  Cluster --> Nodes["System and optional node groups"]
  Cluster --> Addons["compute/eks/addons"]
  Addons --> Controllers["Karpenter, EBS CSI, LB controller, ESO"]
  Addons --> Observability["AMP, OTel, Loki, Alloy, Grafana"]
  Definition --> Service["compute/eks_service"]
  Service --> ECR["Optional ECR repository"]
  Service --> TG["ALB target group and listener rule"]
  Definition --> Charts["Web, worker, and cron Helm charts"]
  Charts --> Workloads["Kubernetes workloads"]
  Workloads --> TG
Loading
Prompt To Fix All With AI
### Issue 1
compute/eks_service/locals.tf:24
**Truncated target-group names collide**

When two load-balanced EKS workloads in the same account and region share the first 24 characters of their names, both resolve to the same target-group name, causing AWS to reject creation of the second target group because that name already exists.

### Issue 2
.github/workflows/helm-charts.yml:26-36
**Action tags remain mutable**

The new workflow references `actions/checkout`, `azure/setup-helm`, and `mikefarah/yq` through mutable tags, allowing upstream tag movement to change the code executed on the runner with access to the checked-out source and read-only repository token. Pin each action to a full commit SHA, matching the repository's existing workflows.

**How this was verified:** Every pre-existing workflow pins action references to full commit SHAs, while these three new references use tags.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "Wire EKS workload and cluster UI metrics..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

Context used (4)

mabadir and others added 30 commits July 20, 2026 21:27
Co-authored-by: Cursor <cursoragent@cursor.com>
…finition

Co-authored-by: Cursor <cursoragent@cursor.com>
…e/eks

Co-authored-by: Cursor <cursoragent@cursor.com>
…e/eks root

Module-level depends_on defers submodule data sources on fresh creates,
making managed policy ARNs unknown at plan time and failing
toset(var.managed_policy_arns) in security/iam. Pass the partition from a
root-level data source into the node group, addons, karpenter, and
fargate profile submodules so policy ARNs stay known during plan.

Co-authored-by: Cursor <cursoragent@cursor.com>
…pute/eks

Installs the amazon-cloudwatch-observability add-on (Container Insights) by
default with a shared Pod Identity role for both cloudwatch-agent and
fluent-bit, and surfaces control plane and Container Insights metrics plus
application/dataplane log groups in the rvn-eks definition UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Keeps compute/eks pure AWS API so the cluster provisions in a single
apply; the Karpenter controller, CRDs, and default NodePool move to a
new compute/eks/components stack with its own rvn-eks-components
definition referencing rvn-eks. Adds a default Ravion Runner security
group so runners can reach private API endpoints.

Co-authored-by: Cursor <cursoragent@cursor.com>
Inputs hidden by show_when resolve to nil; fall back to the exact
Terraform defaults for public_access_cidrs and the Karpenter
namespace/service account per the updated config conventions.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… addons stack, gate Karpenter

Co-authored-by: Cursor <cursoragent@cursor.com>
…ation

Co-authored-by: Cursor <cursoragent@cursor.com>
…ons authenticate via get-token --role-arn

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds public/private ALB and NLB toggles composing the networking/alb and
networking/nlb modules, mirroring the rvn-ecs-cluster shared-LB pattern.
Each enabled load balancer gets an ingress rule admitting its security
group on the EKS cluster security group so it can reach pod IPs, and
listener/security-group/DNS outputs are exposed for workload modules to
attach target groups via the ALB controller's TargetGroupBinding. The
cluster module now passes public_subnet_ids through for public LBs.
…alancer

The controller is no longer a form toggle: it installs when any of the
four load balancer toggles is on, since workload target registration
(TargetGroupBinding) depends on it. lb_controller_enabled now defaults
to false and remains as an advanced-variable opt-in for Ingress-driven
provisioning without shared load balancers. Also merges the two ALB
form sections into one with public/private toggles mirroring the NLB
section, and groups all load balancer fields together after the AWS-API
add-ons.
The controller has no toggle; its chart version field moves next to
deletion protection as 'Load balancer controller chart version'.
A release left in the cluster by a deleted module instance made fresh
installs fail with 'cannot re-use a name that is still in use'. All
addons Helm releases now use upgrade --install semantics so an apply
adopts an existing same-named release instead of erroring.
# Conflicts:
#	Makefile
#	README.md
#	compute/eks/addons/modules/eks_karpenter/README.md
#	compute/eks/modules/eks_cluster/README.md
#	compute/eks/modules/eks_fargate_profile/README.md
#	compute/eks/modules/eks_node_group/README.md
rvn-eks-web, rvn-eks-worker, and rvn-eks-cron could only deploy a
pre-built image, which is the ECS build_source: image_registry path
only. They now offer Dockerfile, Railpack, or registry image, matching
the ECS service family.

Builds need somewhere to push, so compute/eks_service gains an optional
ECR repository gated on ecr_repository_creation_enabled, mirroring
compute/ecs_service. To let worker and cron share that root module, the
load balancer is now gated on a nullable listener_arn via
local.enable_load_balancer, and the target group, listener rule, and
load balancer data sources are counted off it. All load balancer
outputs return null when it is disabled.

Worker and cron were previously deploy-only. They gain a Terraform
stack that creates the ECR repository and nothing else.

Also fixes vpc_id on the workload cluster reference, which read
ref.stack.output.vpc_id and so resolved only after the cluster stack had
applied, leaving the required field empty while adding a workload. It
now reads ref.input.vpc_id, matching ECS.

Adds Terratest coverage for compute/eks_service across the four
configurations: load balancer only, ECR only, both, and repository name
override.
…role

metrics_enabled turns on a Prometheus pipeline that lives entirely in the
customer's account: an Amazon Managed Prometheus workspace (created, or brought
with amp_workspace_id), kube-state-metrics, and a single-replica OpenTelemetry
collector running the ADOT image. The collector scrapes cAdvisor and the
kubelet's resource endpoint through the API server proxy - so it works unchanged
on private-endpoint clusters - plus kube-state-metrics in-cluster, keeps a
curated ~34-family allow-list with a `keep` action in metric_relabel_configs,
and remote-writes the survivors signed with SigV4 through the sigv4auth
extension. Write identity is EKS Pod Identity scoped to aps:RemoteWrite on the
single workspace ARN.

The allow-list is the load-bearing part: AMP bills per sample, so everything
outside locals.metrics_*_allowlist is dropped before it enters collector memory.
cAdvisor's id/name/image labels are dropped, and its empty-container aggregate
rows are dropped for the CPU/memory/OOM families but kept for the network
families, which only exist on those rows.

With metrics on, the amazon-cloudwatch-observability add-on is trimmed to logs
only ({"containerInsights":{"enabled":false},"applicationSignals":{"enabled":
false},"containerLogs":{"enabled":true}}) - the two pipelines measure the same
containers, and the coarser one is the one billed per metric. An explicit
cloudwatch_observability_addon_configuration_values always wins, and a
precondition catches add-on versions older than v6.0.0, whose schema has no such
keys. The log destinations become part of the module contract:
container_log_group, dataplane_log_group, and log_stream_template - which
records that Fluent Bit writes node-first stream names, so a stream prefix
cannot scope to a workload.

grafana_role_enabled adds a read-only role trusted by grafana.amazonaws.com with
an aws:SourceAccount condition: PromQL against the workspace, Logs Insights
against the cluster's log groups. No Grafana workspace is provisioned - that
needs organization-level identity wiring.

Definition YAML gains a "Metrics (Amazon Managed Prometheus)" section and a
0.5.0 release. Tests cover the toggle matrix, allow-list composition, endpoint
derivation, the Container Insights default and its override, and IAM scoping.
Replaces the Container-Insights-logs-only trim from 905cd2f. logs_enabled now
installs Grafana Alloy as a DaemonSet reading every container's stdout off its
own node, and Loki in single-binary mode indexing it with every chunk stored in
an S3 bucket in the customer's account. cloudwatch_observability_enabled flips
to false and stays as a legacy toggle: with Loki for logs and AMP for metrics it
duplicates both halves at CloudWatch prices.

Loki is never exposed — no ingress, no load balancer, not even the chart's nginx
gateway. Ravion reads it by asking Beacon to proxy a query over the WebSocket it
already holds, which is why loki_endpoint is an in-cluster Service URL and why
there is no certificate, no auth layer and no inbound path to open.

The label set is the contract the dashboard's LogQL layer is written against:
namespace, app and workload as labels, level as structured metadata, and
deliberately nothing per-pod — a pod-name label turns one stream per workload
into one per replica per restart. Alloy also drops the filename label
loki.source.file adds, because the path contains the pod UID and would smuggle
the same cardinality back in through the side door.

Retention is enforced twice on purpose. Loki's compactor is the authority
(retention_enabled is off in stock Loki, which is why a Loki bucket usually
grows forever, and why the IAM role carries s3:DeleteObject). The bucket's
lifecycle rule expires a week later, so it never races the compactor into
deleting an index still being read.

Two things found while rendering the charts rather than reading them: with
persistence off the loki chart mounts nothing at /var/loki and the container has
a read-only root filesystem, so Loki cannot write its WAL at all — an emptyDir
now fills that gap; and grafana/grafana on grafana.github.io is deprecated as of
January 2026, so the in-cluster Grafana pulls the maintained chart from
grafana-community instead.

grafana_enabled adds that Grafana, preprovisioned with AMP over SigV4 (its own
Pod Identity role, plus the grafana.ini flag without which SigV4 silently fails)
and Loki over in-cluster HTTP. grafana_role_enabled stays for Amazon Managed
Grafana, which can query AMP but cannot reach a ClusterIP Service.

Beacon's proxy allowlist is wired from this module but the chart has no value
key for it yet — see the PENDING BEACON CHART CONTRACT comment in loki.tf.
tests/logs.tftest.hcl adds the toggle matrix for the logs half: logs off renders
no bucket, no releases and no IAM; a bring-your-own bucket suppresses creation
while every derived value still resolves; retention reaches both the compactor
and the bucket rule; Loki really is single-binary with the caches, gateway and
MinIO off and no static credentials; and the Alloy label contract is asserted
name by name, including the absence of a pod label — that assertion is the point
of the file, because breaking it breaks the dashboard silently and expensively.

tests/metrics.tftest.hcl drops the Container Insights runs and instead asserts
the add-on is off by default.

README gains the Loki/Alloy/S3 and Grafana sections — the label contract, the
two-place retention, why persistence is opt-in, and the split between in-cluster
Grafana and Amazon Managed Grafana — plus updated inputs and outputs tables.
The definition YAML gains Logs and Grafana sections, drops Container Insights to
off, and bumps to 0.6.0.
The dashboard's Prometheus read path had no producer: no definition
declared a prometheus metric source, worker and cron declared no metrics
at all, and the cluster module's charts pointed at ContainerInsights,
which the add-ons module now defaults off.

- rvn-eks-web/worker/cron 0.3.0: golden-signal pod charts (CPU, memory,
  restarts, network, plus replicas or run outcomes) from the add-ons
  module's AMP workspace, and a Loki log source served through Beacon.
  Worker and cron gain an optional EKS Add-ons reference; web reuses its
  existing one with two new AMP mapped inputs.
- rvn-eks-addons 0.7.0: cluster-health charts (node CPU/memory,
  readiness, pod counts) from its own AMP outputs; README now states the
  real Container Insights default.
- rvn-eks 0.2.0: drop the dead ContainerInsights charts, keep the
  AWS/EKS control-plane ones.

# ELBv2 target group names are capped at 32 characters and the "-tg" suffix
# takes 3, mirroring the ECS service module's truncation.
target_group_name = "${substr(var.name, 0, min(length(var.name), 24))}-tg"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Truncated target-group names collide

When two load-balanced EKS workloads in the same account and region share the first 24 characters of their names, both resolve to the same target-group name, causing AWS to reject creation of the second target group because that name already exists.

Knowledge Base Used: Networking modules: VPC, load balancers, DNS, security groups, EIPs

Prompt To Fix With AI
This is a comment left during a code review.
Path: compute/eks_service/locals.tf
Line: 24

Comment:
**Truncated target-group names collide**

When two load-balanced EKS workloads in the same account and region share the first 24 characters of their names, both resolve to the same target-group name, causing AWS to reject creation of the second target group because that name already exists.

**Knowledge Base Used:** [Networking modules: VPC, load balancers, DNS, security groups, EIPs](https://app.greptile.com/flightcontrol/-/custom-context/knowledge-base/ravionhq/modules/-/docs/networking.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +26 to +36
uses: actions/checkout@v4

- name: Setup Helm
uses: azure/setup-helm@v4
with:
version: v3.16.3

# yq is preinstalled on ubuntu-latest runners; pinned here so the
# assertion syntax in charts/test.sh cannot drift underneath us.
- name: Setup yq
uses: mikefarah/yq@v4.44.3

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 security Action tags remain mutable

The new workflow references actions/checkout, azure/setup-helm, and mikefarah/yq through mutable tags, allowing upstream tag movement to change the code executed on the runner with access to the checked-out source and read-only repository token. Pin each action to a full commit SHA, matching the repository's existing workflows.

How this was verified: Every pre-existing workflow pins action references to full commit SHAs, while these three new references use tags.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/helm-charts.yml
Line: 26-36

Comment:
**Action tags remain mutable**

The new workflow references `actions/checkout`, `azure/setup-helm`, and `mikefarah/yq` through mutable tags, allowing upstream tag movement to change the code executed on the runner with access to the checked-out source and read-only repository token. Pin each action to a full commit SHA, matching the repository's existing workflows.

**How this was verified:** Every pre-existing workflow pins action references to full commit SHAs, while these three new references use tags.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

mabadir added 19 commits August 17, 2026 20:49
Chart 0.3.0 carries the agent's remediation commands, Helm-storage-sourced
drift, and diagnosis reporting, and drops three read grants (ingresses,
persistentvolumeclaims, targetgroupbindings). The chart version is now
pinned per module release instead of resolving the registry's latest at
apply time, so a chart (RBAC) change arrives as a visible module upgrade.
logs_providers and metrics_providers replace the logs_enabled / metrics_enabled
booleans: Loki and AMP are the defaults, every other destination is a member of
the same lists, and each provider carries its own settings object. Rendering
providers are published in a fixed fallback order (loki -> cloudwatch, amp ->
prometheus -> cloudwatch) rather than assumed.

The old booleans stay one release as fallbacks, so an instance that had a signal
off stays off and an instance that had Container Insights on upgrades into
[amp, cloudwatch].
A vendor API key is a Secrets Manager ARN in and a Kubernetes Secret out: the
operator reads it with its own Pod Identity role and the collectors read it as
an environment variable, so no token is ever a Helm value, a Terraform output,
or a line in Helm release history. Selecting a vendor with the operator off
fails the plan rather than installing a collector that cannot authenticate.
Alloy gains one loki.write per selected loki-family destination, and a second
collector - the OpenTelemetry contrib DaemonSet - carries CloudWatch Logs,
Datadog, New Relic and custom OTLP behind one filelog receiver. Files are tailed
once however many destinations are selected, and neither collector runs unless
its half of the selection is non-empty.

logs_namespace_exclude keeps named namespaces out of both: Alloy drops them at
discovery, the OpenTelemetry collector never opens their files.
The metrics collector keeps its single curated scrape and grows one exporter per
selected provider: AMP over SigV4 as today, Grafana Cloud remote write with
basic auth, Datadog, New Relic and custom OTLP over OTLP/HTTP. The image follows
the selection - the AWS Distro for an AMP-only cluster, upstream contrib when a
vendor exporter it does not ship is selected - and both remain overridable.
The amazon-cloudwatch-observability add-on is installed because cloudwatch is in
logs_providers or metrics_providers, never as a section of its own and never by
default. Its two halves follow the two lists: Fluent Bit only for logs, the
metrics agent only for metrics.

Auto-Monitor is pinned off in the add-on's configuration. Left at its default it
injects the AWS Distro agent into every workload in the cluster and restarts the
pods to do it, which is where the Application Signals noise on ravion-test came
from. Application Signals is now an explicit toggle, and with a namespace list
the cluster-wide switch stays off.
The outputs the service modules and the control plane read: the selected
providers, the rendering chains in fallback order, the CloudWatch log group, the
per-vendor deep links, the Grafana Cloud query URLs, and the name of the Secret
Beacon presents when it proxies a query.

Beacon's allowlist grows past the in-cluster Loki to every external store Ravion
renders from, each paired with an ESO-materialized credential Secret the agent
resolves by name - the control plane never sees the value.
Fifteen runs over the selection logic: what a default instance installs (and
that nothing CloudWatch does), how the deprecated booleans map onto the lists,
Auto-Monitor staying off, both collectors fanning out, credentials arriving by
reference, and the two preconditions that refuse a vendor with no way to
authenticate. The existing files opt into providers explicitly.
The add-ons module now lets a user pick any number of logs and metrics
providers, and a workload has to follow that choice rather than assume
Loki and AMP. The ui block resolves with no ref scope, so every value the
Logs and Metrics tabs need has to arrive as a mapped input, the way the
AMP identifiers already do.

Renames the AMP partial to cover observability as a whole and adds the
two rendering-provider lists, the CloudWatch log group, the in-cluster
Prometheus endpoint, the vendor link lists, and the Grafana Cloud query
URLs and credentials secret the Beacon proxy will need.
The form loses the Container Insights section and gains a provider multi-select
per signal, with only the chosen providers' fields on screen. Logs and Metrics
are on by default, so a new cluster renders both tabs with nothing filled in,
and each section's description now says what runs, what it costs, and that
CloudWatch is never one of the defaults.

The stack mapping folds each toggle into its provider list and passes one object
per provider; the deprecated cloudwatch_observability_enabled stays one release
so an instance that had Container Insights keeps it as the fallback behind AMP.

The generated README table also picks up the other EKS definitions' versions,
which were stale on main.
Every entry keeps id: app so the tab treats them as one fallback chain
rather than several sources to merge: the in-cluster store first, then
CloudWatch Logs, so an offline Beacon agent degrades to CloudWatch
instead of to an empty tab. Ship-only providers add an Open in <vendor>
action alongside.

The vendor entries are array spreads filtered to one provider each. The
add-ons module publishes a link only for a provider the user selected, so
an unselected vendor contributes no entry and needs no guard, and each
link can still carry that vendor's own search syntax.

An add-ons module older than 0.8.0 publishes no provider list at all, and
those workloads keep reading Loki.
Each signal now appears once per rendering provider under a shared chart
id, in the add-ons module's fallback order: Amazon Managed Prometheus,
then an in-cluster Prometheus over the same PromQL, then CloudWatch
Container Insights. Ship-only providers add an Open in <vendor> action.

Container Insights aggregates pods under a PodName dimension that is the
controlling object's name with the generated suffix stripped, which for
these charts is exactly the module name for Deployments and CronJobs
alike - the identity that makes a CloudWatch link possible at all, since
a dimension cannot be matched by prefix. The CloudWatch entries use
pod_cpu_usage_total and pod_memory_working_set so the chain plots the
same quantity throughout, and Average rather than Sum so a chart does not
change shape when the dashboard picks a longer period.

Replica counts fall back to a Service pod count on rvn-eks-web only, and
CronJob run outcomes have no CloudWatch equivalent at all; both are
called out where they stop.
Documents the Metrics and Logs tabs, which 0.3.0 added without a readme
section: how the fallback chain reads, what CloudWatch measures
differently from Prometheus and where its charts stop, and that the
add-ons module is the only place observability is configured.

Refreshing the README table also picks up the rvn-eks and rvn-eks-addons
rows, which were already behind their definitions.
…etheus

Logs gain two ship-only destinations - Amazon OpenSearch Service, signed with the
collector's own Pod Identity role rather than a key, and Splunk over HEC.

Metrics gain a store that is not AWS's: Prometheus in the cluster, installed with
its remote-write receiver on and a persistent volume behind it, or an endpoint
you already run. It is a rendering provider, read through Beacon like the
in-cluster log store, and sits behind Amazon Managed Prometheus in the chain.
logs_enabled, metrics_enabled and cloudwatch_observability_enabled are gone from
the Terraform surface: the provider lists are the only switch, and an instance
that passed through 0.8.0 or 0.8.1 already carries the selection they mapped to.

The service modules' contract is tightened where it matters to them: the
provider and link lists are always lists and never null (null means 'add-ons
older than providers'), and the Datadog metrics link now ends at the explorer's
scope parameter, which is what the workload chart appends to.
A map literal in predicate position must be parenthesised; the bare form
threw a syntax error the moment a service set image_pull_secret_names.
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown

Ravion Module Publish Plan

Dry run only. No Ravion API mutations were made.

Module Current Version New Version Description
rvn-eks n/a 0.2.0 Drop the Container Insights charts from the Metrics tab. The EKS Add-ons module defaults Container Insights off, so those charts rendered empty on new clusters; cluster-health charts now live on the add-ons module, read from its Amazon Managed Prometheus workspace. The control-plane charts (API server requests, errors, throttling, pending pods) remain - EKS publishes those under AWS/EKS with no agent involved.
rvn-eks-addons n/a 0.8.4 Beacon chart 0.4.1, and beacon_image_tag is a plain pin. Every release so far ignored the tag after its first apply (the original "floor, not a pin" design), which froze whatever tag was first applied into the state for good: a cluster once given a since-retired tag was rolled back to it on every upgrade and wedged when that image could not start. Now the pin is asserted for exactly as long as it is configured and removing it hands the version back to the control plane on the next apply. The 0.4.1 chart preserves the running image whole (registry included, so a stale image.repository in beacon_helm_values no longer re-renders a tag that registry never held) and only when the release's rollout has settled; a wedged release takes the chart's floor, so a plain re-apply repairs it. If your instance has beacon_image_tag or an image.repository override in its advanced variables from before 0.8.0, remove both when upgrading. Previously (0.8.3): Beacon chart 0.4.0 - an add-ons apply no longer moves the agent version; the chart re-emits the running image on every helm upgrade, and gains httpProxy.credentials for rendering Grafana Cloud and in-cluster Prometheus through the agent. Previously (0.8.2): the pre-0.8.0 logs_enabled / metrics_enabled / cloudwatch_observability_enabled Terraform variables are gone; the provider lists are the only switch. An instance still on 0.7.x should upgrade to 0.8.1 first, which is what reads them.
rvn-eks-cron n/a 0.4.0 Follow the observability providers chosen on the EKS add-ons module. The Metrics and Logs tabs read whichever stores that module selected, falling back in order when one cannot answer - so a cluster that also ships to CloudWatch keeps showing logs while the in-cluster agent is offline - and providers that ship to a vendor add an "Open in ..." action pointing at this job. Run outcome charts still need a Prometheus provider.
rvn-eks-web n/a 0.4.0 Follow the observability providers chosen on the EKS add-ons module. The Metrics and Logs tabs read whichever stores that module selected, falling back in order when one cannot answer - so a cluster that also ships to CloudWatch keeps showing logs while the in-cluster agent is offline - and providers that ship to a vendor add an "Open in ..." action pointing at this service.
rvn-eks-worker n/a 0.4.0 Follow the observability providers chosen on the EKS add-ons module. The Metrics and Logs tabs read whichever stores that module selected, falling back in order when one cannot answer - so a cluster that also ships to CloudWatch keeps showing logs while the in-cluster agent is offline - and providers that ship to a vendor add an "Open in ..." action pointing at this worker.

Diffs

rvn-eks n/a -> 0.2.0

--- remote
+++ compiled
-
+description: Production-ready Amazon EKS cluster with a system node group, core add-ons, and optional Fargate compute. Extend with the EKS Add-ons module (Karpenter, load balancer controller, EBS CSI, Container Insights).
+name: EKS Cluster
+type: rvn-eks

rvn-eks n/a -> 0.2.0

--- remote
+++ compiled
+inputs:
+  - id: network
+    immutable: true
+    label: VPC network
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Override the VPC, subnet, and security group for Pipeline Terraform runners. Must use the same AWS account as selected above.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_vpc
+        label: VPC
+        type: section
+      - default: <<ref.stack.output.vpc_id>>
+        id: vpc_id
+        immutable: true
+        label: VPC ID
+        required: true
+        type: string
+      - add_button_label: Add private subnet ID
+        default: <<ref.stack.output.private_subnet_ids>>
+        description: Subnets for the EKS control plane and default node placement. Use private subnets in at least two availability zones.
+        id: subnet_ids
+        immutable: true
+        label: Private subnet IDs
+        required: true
+        type: string_array
+      - add_button_label: Add public subnet ID
+        collapsible: true
+        default: <<ref.stack.output.public_subnet_ids>>
+        description: Public subnets made available to dependent modules, such as EKS Add-ons shared load balancers. Not used by the cluster itself.
+        id: public_subnet_ids
+        label: Public subnet IDs
+        type: string_array
+    required: true
+    type: $ref:rvn-aws-network
+  - id: section_cluster
+    label: EKS cluster
+    type: section
+  - default: <<project.given_id>>-<<environment.given_id>>
+    description: Name of the EKS cluster and prefix for related resources.
+    id: name
+    immutable: true
+    label: Name slug
+    patterns:
+      - message: 1-100 letters, numbers, hyphens, and underscores. Start with a letter or number.
+        pattern: ^[0-9A-Za-z][A-Za-z0-9-_]{0,99}$
+    required: true
+    type: string
+  - default: $values:first
+    description: Kubernetes version for the EKS cluster.
+    id: kubernetes_version
+    label: Kubernetes version
+    required: true
+    type: string
+    values: $values:aws/eks_versions?region=<<module.input.aws_region>>&currentVersion=<<instance.input.kubernetes_version>>
+  - default: true
+    description: Prevent the cluster from being deleted via the AWS API. Must be turned off before this module can be destroyed.
+    id: deletion_protection_enabled
+    label: Deletion protection
+    type: boolean
+  - collapsible: true
+    default: true
+    description: Envelope-encrypt Kubernetes secrets with a KMS key. A key is created automatically unless an existing key ARN is provided below.
+    id: secrets_encryption_enabled
+    label: Secrets encryption
+    type: boolean
+  - collapsible: true
+    description: Existing KMS key for Kubernetes secrets encryption. Leave blank to create a dedicated key.
+    id: secrets_kms_key_arn
+    label: Secrets KMS key ARN
+    placeholder: arn:aws:kms:...
+    show_when:
+      secrets_encryption_enabled: true
+    type: string
+  - description: Controls how the Kubernetes API server endpoint can be reached. Private access keeps traffic inside the VPC; public access exposes the endpoint to the internet.
+    id: section_endpoint
+    label: API endpoint access
+    type: section
+  - default: true
+    description: Allow access to the Kubernetes API server from inside the VPC.
+    id: private_endpoint_access_enabled
+    label: Private endpoint access
+    type: boolean
+  - default: false
+    description: Allow access to the Kubernetes API server from the public internet.
+    id: public_endpoint_access_enabled
+    label: Public endpoint access
+    type: boolean
+  - add_button_label: Add CIDR block
+    description: IPv4 CIDR blocks allowed to reach the public API server endpoint. Terraform defaults to 0.0.0.0/0.
+    id: public_access_cidrs
+    label: Public access CIDRs
+    placeholder: 0.0.0.0/0
+    show_when:
+      public_endpoint_access_enabled: true
+    type: string_array
+  - default: true
+    description: Create a security group allowed to reach the Kubernetes API endpoint. Attach it to the Ravion execution environment used by modules that talk to the cluster (such as EKS Add-ons with Karpenter) so their pipeline runs can reach a private endpoint.
+    id: ravion_runner_security_group_creation_enabled
+    label: Ravion Runner security group
+    type: boolean
+  - default: true
+    description: Create an IAM role that Ravion Runner step executions assume for Kubernetes API access, registered as an EKS access entry with cluster-admin. Used by the EKS Add-ons module to install Helm charts.
+    id: ravion_runner_role_creation_enabled
+    label: Ravion Runner role
+    type: boolean
+  - description: Required managed node group that runs system workloads such as CoreDNS. Sized small by default; add more compute with additional node groups, Karpenter, or Fargate.
+    id: section_system_nodes
+    label: System node group
+    type: section
+  - add_button_label: Add instance type
+    default:
+      - t3.medium
+    description: EC2 instance types for system nodes.
+    id: system_node_instance_types
+    label: Instance types
+    placeholder: t3.medium
+    type: string_array
+  - default: ON_DEMAND
+    description: Spot is cheaper but nodes can be interrupted. Use On-demand for system workloads unless cost is critical.
+    id: system_node_capacity_type
+    label: Capacity type
+    type: string
+    values:
+      - label: On-demand
+        value: ON_DEMAND
+      - label: Spot
+        value: SPOT
+  - default: 2
+    description: Minimum system nodes. Also used as the initial node count; after creation, node count is managed outside Terraform.
+    id: system_node_min_size
+    label: Min nodes
+    min: 1
+    type: number
+  - default: 4
+    description: Maximum system nodes.
+    id: system_node_max_size
+    label: Max nodes
+    min: 1
+    type: number
+  - collapsible: true
+    description: Root EBS volume size for system nodes. Leave blank for the AMI default.
+    id: system_node_disk_size
+    label: Disk size (GB)
+    min: 20
+    placeholder: "20"
+    type: number
+  - collapsible: true
+    default: {}
+    description: Optional additional managed node groups keyed by name. Each value follows the composite module's additional_node_groups object shape (instance_types, capacity_type, min_size, max_size, labels, taints, and more).
+    id: additional_node_groups
+    label: Additional node groups
+    type: object
+  - description: Run selected namespaces on AWS Fargate instead of EC2 nodes.
+    id: section_fargate
+    label: Fargate
+    type: section
+  - collapsible: true
+    default: {}
+    description: "Optional Fargate profiles keyed by name. Each value follows the composite module's fargate_profiles object shape, for example {\"selectors\": [{\"namespace\": \"my-namespace\"}]}."
+    id: fargate_profiles
+    label: Fargate profiles
+    type: object
+  - description: Additional EKS access entries for IAM principals that need cluster access. The IAM principal that creates the cluster is granted admin access automatically. Automatic access for Ravion deploys will be wired here in a future release.
+    id: section_access
+    label: Cluster access
+    type: section
+  - collapsible: true
+    default: {}
+    description: Map of access entries keyed by a stable identifier. Each value follows the composite module's access_entries object shape (principal_arn, type, kubernetes_groups, policy_associations).
+    id: access_entries
+    label: Access entries
+    type: object
+  - id: section_observability
+    label: Observability
+    type: section
+  - add_button_label: Add log type
+    default:
+      - api
+      - audit
+      - authenticator
+    description: Control plane log types shipped to CloudWatch Logs. Remove all entries to disable control plane logging.
+    id: enabled_cluster_log_types
+    label: Control plane log types
+    type: string_array
+    values:
+      - label: API server
+        value: api
+      - label: Audit
+        value: audit
+      - label: Authenticator
+        value: authenticator
+      - label: Controller manager
+        value: controllerManager
+      - label: Scheduler
+        value: scheduler
+  - collapsible: true
+    default: 30
+    description: Retention in days for the control plane CloudWatch log group.
+    id: cluster_log_retention_in_days
+    label: Log retention (days)
+    min: 1
+    type: number
+  - id: section_misc
+    label: Misc
+    type: section
+  - collapsible: true
+    description: A map of tags to assign to all resources. Default tags are `Owner`, `ProjectGivenId`, `EnvironmentGivenId`, `ModuleGivenId`, `ModuleId`
+    id: tags
+    label: Tags
+    required: false
+    type: keyvalue
+  - id: section_advanced
+    label: Terraform settings
+    type: section
+  - collapsible: true
+    description: Override the environment's default version for this module
+    id: opentofu_version
+    label: OpenTofu version override
+    required: false
+    type: string
+    values: $values:opentofu/versions
+  - collapsible: true
+    description: Override Terraform state backend workspace name. Defaults to project + environment + module given ids.
+    id: ravion_state_backend_workspace
+    immutable: true
+    label: Ravion Terraform workspace name
+    type: string
+  - collapsible: true
+    default: {}
+    description: Optional raw Terraform variable overrides for advanced module inputs or one-off overrides. Values here override the generated variables above.
+    id: advanced_terraform_variables
+    label: Advanced Terraform variables
+    required: false
+    type: object
+readme: |-
+  Production-ready Amazon EKS cluster with a system node group, core add-ons, and optional Fargate compute. Extend with the **EKS Add-ons** module (Karpenter, load balancer controller, EBS CSI, Container Insights).
 
+  ## Overview
+
+  Amazon EKS (Elastic Kubernetes Service) runs managed Kubernetes control planes on AWS. This module creates an EKS cluster inside your selected VPC and provisions everything a working cluster needs, in the correct order:
+
+  1. **Cluster** - control plane, OIDC provider, secrets encryption, VPC CNI, kube-proxy, Pod Identity Agent, and the AWS Load Balancer Controller IAM role
+  2. **System node group** - a small managed node group that gives system workloads somewhere to run
+  3. **CoreDNS** - installed only after compute exists so it starts healthy
+  4. **Optional compute** - additional managed node groups and Fargate profiles
+
+  This module talks only to the AWS API, so it provisions in a single apply. Optional extensions - Karpenter autoscaling, the AWS Load Balancer Controller, the EBS CSI driver, and Container Insights - are added by the separate **EKS Add-ons** module, so clusters only carry what they use.
+
+  Terraform source: [ravionhq/modules/compute/eks](https://github.com/ravionhq/modules/tree/rvn-eks@0.2.0/compute/eks)
+
+  ## Use cases
+
+  | Scenario                          | EKS cluster helps by...                                          |
+  | --------------------------------- | ---------------------------------------------------------------- |
+  | Running Kubernetes workloads      | Providing a managed control plane and ready-to-use node group    |
+  | Autoscaling, ingress, storage, observability | Pairing 
... diff truncated ...

rvn-eks-addons n/a -> 0.8.4

--- remote
+++ compiled
-
+description: Selectable add-ons for an existing EKS cluster - Karpenter autoscaling, the AWS Load Balancer Controller, the External Secrets Operator, EBS CSI storage, workload logs and metrics shipped to any combination of destinations (an in-cluster log store on S3 and Amazon Managed Prometheus by default; CloudWatch, Grafana Cloud, Datadog, New Relic or a custom OTLP endpoint on request), Ravion EKS Management via the in-cluster Beacon agent, and shared application/network load balancers, each toggled and configured independently.
+name: EKS Add-ons
+type: rvn-eks-addons

rvn-eks-addons n/a -> 0.8.4

--- remote
+++ compiled
+inputs:
+  - id: cluster
+    immutable: true
+    label: EKS cluster
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Execution environment for Pipeline Terraform runners. Defaults to the cluster module's execution environment. When Karpenter is enabled on a private cluster, it must run inside the cluster VPC with the cluster's Ravion Runner security group attached so Helm can reach the Kubernetes API endpoint.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_cluster
+        label: EKS cluster
+        type: section
+      - default: <<ref.stack.output.cluster_name>>
+        id: cluster_name
+        immutable: true
+        label: Cluster name
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_role_arn>>
+        description: IAM role assumed for Kubernetes API authentication when installing Helm charts. Defaults to the cluster's Ravion Runner role.
+        id: ravion_runner_role_arn
+        label: Ravion Runner role ARN
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.cluster_security_group_id>>
+        description: EKS-managed cluster security group attached to Karpenter-launched nodes.
+        id: cluster_security_group_id
+        label: Cluster security group ID
+        type: string
+      - add_button_label: Add subnet ID
+        collapsible: true
+        default: <<ref.stack.output.node_subnet_ids>>
+        description: Subnets the default Karpenter NodePool launches nodes into. Also used by internal shared load balancers.
+        id: node_subnet_ids
+        label: Node subnet IDs
+        type: string_array
+      - add_button_label: Add subnet ID
+        collapsible: true
+        default: <<ref.stack.output.public_subnet_ids>>
+        description: Public subnets for internet-facing shared load balancers.
+        id: public_subnet_ids
+        label: Public subnet IDs
+        type: string_array
+    required: true
+    type: $ref:rvn-eks
+  - description: Ravion's in-cluster agent, Beacon. It dials Ravion outbound over a single WebSocket - nothing ever reaches into the cluster - and reports workload, rollout, and node state back, which is what makes a private-endpoint cluster observable from Ravion at all. Optionally it also runs Ravion's deploys from inside the cluster. Requires Kubernetes API connectivity from the Terraform runner for the install itself.
+    id: section_beacon
+    label: Ravion EKS Management
+    type: section
+  - default: false
+    description: Register this cluster with the Ravion control plane and install the Beacon agent. Ravion issues the agent's credential during the deployment - there is nothing to paste - and it is written into a Kubernetes secret and mirrored into AWS Secrets Manager in your own account. The agent is read-only unless Beacon-run deployments below are enabled. Advanced settings - the agent WebSocket endpoint, Helm chart version, install namespace, and the namespaces the agent may observe - are available through Advanced Terraform variables.
+    id: beacon_enabled
+    label: Ravion EKS Management
+    type: boolean
+  - default: false
+    description: Let Beacon run Ravion's deploys from inside the cluster instead of Ravion reaching in from outside. In the namespaces below the agent can create, update, and delete workload objects; it can never create RBAC objects, namespaces, or anything cluster-scoped. Leaving this off still gives a fully working agent - deploys continue to run from outside the cluster.
+    id: beacon_deploy_enabled
+    label: Beacon-run deployments
+    show_when:
+      beacon_enabled: true
+    type: boolean
+  - add_button_label: Add namespace
+    collapsible: true
+    description: Namespaces Beacon may deploy into. Falls back to the observed namespaces (beacon_namespace_scope) when empty. If both are empty the install fails rather than granting cluster-wide write - there is deliberately no deploy-everywhere posture.
+    id: beacon_deploy_namespaces
+    label: Deploy namespaces
+    placeholder: default
+    show_when:
+      beacon_deploy_enabled: true
+    type: string_array
+  - description: Just-in-time node autoscaling. Provisions Karpenter end to end - controller and node IAM roles, Pod Identity association, instance profile, interruption queue, EventBridge rules, the controller Helm charts, and a default NodePool. Requires Kubernetes API connectivity from the Terraform runner.
+    id: section_karpenter
+    label: Karpenter
+    type: section
+  - default: true
+    id: karpenter_enabled
+    label: Karpenter
+    type: boolean
+  - collapsible: true
+    description: Version of the Karpenter Helm chart (and karpenter-crd chart) to install.
+    id: karpenter_chart_version
+    label: Chart version
+    placeholder: 1.14.0
+    show_when:
+      karpenter_enabled: true
+    type: string
+  - collapsible: true
+    description: Namespace where the Karpenter controller is installed.
+    id: karpenter_controller_namespace
+    label: Controller namespace
+    placeholder: kube-system
+    show_when:
+      karpenter_enabled: true
+    type: string
+  - collapsible: true
+    description: Service account name used by the Karpenter controller.
+    id: karpenter_controller_service_account
+    label: Controller service account
+    placeholder: karpenter
+    show_when:
+      karpenter_enabled: true
+    type: string
+  - default: true
+    description: Create a general-purpose default NodePool and EC2NodeClass so Karpenter can provision nodes out of the box. Disable to manage NodePools yourself.
+    id: karpenter_default_node_pool_enabled
+    label: Default NodePool
+    show_when:
+      karpenter_enabled: true
+    type: boolean
+  - description: EBS-backed persistent volumes via the aws-ebs-csi-driver EKS add-on and its Pod Identity role.
+    id: section_ebs_csi
+    label: EBS CSI driver
+    type: section
+  - default: false
+    id: ebs_csi_driver_enabled
+    label: EBS CSI driver
+    type: boolean
+  - collapsible: true
+    description: Pinned add-on version. Leave blank to let AWS resolve the most recent compatible version.
+    id: ebs_csi_addon_version
+    label: Add-on version
+    placeholder: Latest compatible
+    show_when:
+      ebs_csi_driver_enabled: true
+    type: string
+  - description: Container output, collected on every node and delivered to the destinations you choose. On by default into a log store that runs inside your cluster and keeps every line in an S3 bucket in your own AWS account - Ravion reads that through the same agent connection Ravion EKS Management uses, so there is no endpoint to secure and no log data leaves your account except in answer to a query. Add CloudWatch Logs or a vendor beside it, or instead of it. Requires Kubernetes API connectivity from the Terraform runner.
+    id: section_logs
+    label: Logs
+    type: section
+  - default: true
+    description: Collect container logs. On by default into the in-cluster store, whose only cost is storage and requests on the S3 bucket plus the pods that run the collector - there is no per-gigabyte ingestion charge. Turn this off to run no collector and create no store; the Logs tab then says logs are off for this cluster. Advanced settings - install namespace, chart versions, resources, and local disk - are available through Advanced Terraform variables.
+    id: logs_enabled
+    label: Logs
+    type: boolean
+  - add_button_label: Add destination
+    default:
+      - loki
+    description: Where the logs go. Pick as many as you like. Ravion's Logs tab reads from the first destination in the first group that can answer, and falls back to the next when it cannot - the in-cluster store, then CloudWatch Logs. Everything in the second group receives a copy and gets an "Open in ..." link in the tab; the collectors read each file once whatever the number of destinations, but every vendor bills for what it receives.
+    id: logs_providers
+    label: Providers
+    show_when:
+      logs_enabled: true
+    type: string_array
+    values:
+      - group_label: Renders in Ravion's Logs tab (read first)
+        label: In-cluster log store (Loki, S3-backed)
+        value: loki
+      - group_label: Renders in Ravion's Logs tab (fallback)
+        label: Amazon CloudWatch Logs
+        value: cloudwatch
+      - group_label: Ships to your vendor
+        label: Grafana Cloud Logs
+        value: grafana_cloud
+      - group_label: Ships to your vendor
+        label: Datadog
+        value: datadog
+      - group_label: Ships to your vendor
+        label: New Relic
+        value: new_relic
+      - group_label: Ships to your vendor
+        label: Amazon OpenSearch Service
+        value: opensearch
+      - group_label: Ships to your vendor
+        label: Splunk (HEC)
+        value: splunk
+      - group_label: Ships to your vendor
+        label: Custom OTLP endpoint
+        value: otlp
+  - default: 30
+    description: How long logs stay searchable in the in-cluster store. Older logs are deleted from the bucket automatically.
+    id: log_retention_days
+    label: Retention (days)
+    show_when:
+      logs_enabled: true
+      logs_providers: loki
+    type: number
+  - collapsible: true
+    description: Store logs in an existing S3 bucket instead of creating one. Leave blank to create a bucket for this cluster. When you bring your own, its lifecycle and encryption settings stay yours to manage.
+    id: loki_s3_bucket
+    label: Existing log bucket
+    show_when:
+      logs_enabled: true
+      logs_providers: loki
+    type: string
+  - default: 30
+    description: Retention on the CloudWatch log group /ravion/eks/<cluster>, which carries one stream per pod. CloudWatch Logs bills per gigabyte ingested and then for storage.
+    id: cloudwatch_logs_retention_days
+    label: CloudWatch retention (days)
+    show_when:
+      logs_enabled: true
+      logs_providers: cloudwatch
+    type: number
+  - description: Grafana Cloud's Loki push URL, from the stack's Logs data source details - for example https://logs-prod-006.grafana.net/loki/api/v1/push.
+    id: grafana_cloud_logs_url
+    label: Grafana Cloud Loki push URL
+    placeholder: https://logs-prod-006.grafana.net/loki/api/v1/push
+    show_when:
+      logs_enabled: true
+      logs_providers: grafana_cloud
+    type: string
+  - description: The numeric user id shown beside that push URL in Grafana Cloud.
+    id: grafana_cloud_logs_user
+    label: Grafana Cloud Loki user
+    show_when:
+      logs_enabled: true
+      logs_providers: grafana_cloud
+    type: string
+  - description: Secrets Manager ARN holding a Grafana Cloud access token with logs:write (and metrics:write, if Grafana Cloud is also a metrics destination). Read in-cluster by External Secrets; never stored by Ravion.
+    id: grafana_cloud_token_secret_arn
+    label: Grafana Cloud token secret
+    placeholder: arn:aws:secretsmanager:us-east-2:111122223333:secret:grafana-cloud-token
+    show_when:
+      logs_enabled: true
+      logs_providers: grafana_cloud
+    type: string
+  - collapsible: true
+    description: Your Grafana Cloud stack URL, used only to build the "Open in Grafana Cloud" link on the Logs and Metrics tabs. Le
... diff truncated ...

rvn-eks-cron n/a -> 0.4.0

--- remote
+++ compiled
-
+description: Scheduled job on EKS for running a container on a cron schedule, deployed from a container image with no chart of your own.
+name: EKS Cron Job
+type: rvn-eks-cron

rvn-eks-cron n/a -> 0.4.0

--- remote
+++ compiled
+build:
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, cache_from: {tag: "dockerfile"}} : module.input.build_source == "railpack" ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  destinations:
+    - id: ecr
+      repository_arn: << stack.output.ecr_repository_arn >>
+      tags:
+        - <<pipeline.run.id>>-<< module.input.build_source >>
+        - << module.input.build_source >>
+      type: ecr
+  environment_variables: << module.input.build_environment_variables >>
+  infrastructure:
+    ami: << module.input.build_ami || nil >>
+    aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
+    execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
+    instance_size: << module.input.build_instance_size >>
+    permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
+    region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
+    type: << module.input.build_infrastructure_type >>
+  inputs:
+    - description: Defaults to repo default branch
+      id: branch
+      label: Git branch
+      required: false
+      type: string
+    - description: Optional commit SHA, tag, or ref to build. Defaults to the configured branch head.
+      id: ref
+      label: Git ref (commit or tag)
+      required: false
+      type: string
+  source:
+    base_path: << module.input.source_base_path || "." >>
+    branch: << build.input.branch >>
+    ref: << build.input.ref >>
+    repo: << module.input.source_repo >>
+    type: git
+  type: '<< module.input.build_source == "image_registry" ? "disabled" : "image" >>'
+deploy:
+  concurrency:
+    queue_overflow: oldest
+    queue_size: 1
+  definition:
+    create_namespace: "<< module.input.create_namespace != nil ? module.input.create_namespace : true >>"
+    engine: helm
+    namespace: << module.input.namespace >>
+    release_name: << module.input.name >>
+    secrets: "<< module.input.secrets != nil ? module.input.secrets : [] >>"
+    source:
+      branch: main
+      chart: charts/rvn-eks-cron
+      ref: rvn-eks-cron@0.4.0
+      repo: https://github.com/ravionhq/modules
+      type: inline
+    values:
+      args: "<< module.input.start_command_args != nil ? module.input.start_command_args : [] >>"
+      command: "<< module.input.start_command != nil ? module.input.start_command : [] >>"
+      concurrencyPolicy: '<< module.input.concurrency_policy != nil ? module.input.concurrency_policy : "Forbid" >>'
+      env: "<< module.input.environment_variables != nil ? module.input.environment_variables : [] >>"
+      failedJobsHistoryLimit: "<< module.input.failed_jobs_history_limit != nil ? module.input.failed_jobs_history_limit : 1 >>"
+      fullnameOverride: << module.input.name >>
+      image:
+        digest: '<< deploy.input.image_ref contains "sha256:" ? deploy.input.image_ref : "" >>'
+        repository: '<< module.input.build_source == "image_registry" ? module.input.image_repository : stack.output.ecr_repository_url >>'
+        tag: '<< deploy.input.image_ref contains "sha256:" ? "" : deploy.input.image_ref >>'
+      imagePullSecrets: '<< module.input.image_pull_secret_names != nil ? map(module.input.image_pull_secret_names, ({"name": #})) : [] >>'
+      job:
+        activeDeadlineSeconds: << module.input.active_deadline_seconds >>
+        backoffLimit: "<< module.input.backoff_limit != nil ? module.input.backoff_limit : 3 >>"
+        restartPolicy: '<< module.input.restart_policy != nil ? module.input.restart_policy : "OnFailure" >>'
+        ttlSecondsAfterFinished: << module.input.ttl_seconds_after_finished >>
+      resources:
+        limits: '<< module.input.cpu_limit ? {"cpu": module.input.cpu_limit, "memory": module.input.memory_limit} : {"memory": module.input.memory_limit} >>'
+        requests:
+          cpu: << module.input.cpu_request >>
+          memory: << module.input.memory_request >>
+      schedule: << module.input.schedule >>
+      startingDeadlineSeconds: << module.input.starting_deadline_seconds >>
+      successfulJobsHistoryLimit: "<< module.input.successful_jobs_history_limit != nil ? module.input.successful_jobs_history_limit : 3 >>"
+      suspend: "<< module.input.suspend != nil ? module.input.suspend : false >>"
+      terminationGracePeriodSeconds: "<< module.input.termination_grace_period_seconds != nil ? module.input.termination_grace_period_seconds : 30 >>"
+      timeZone: '<< module.input.time_zone != nil ? module.input.time_zone : "" >>'
+  infrastructure:
+    cluster_arn: << module.input.cluster_arn >>
+    cluster_certificate_authority_data: << module.input.cluster_certificate_authority_data >>
+    cluster_endpoint: << module.input.cluster_endpoint >>
+    cluster_name: << module.input.cluster_name >>
+    execution_environment_id: << deploy.input.execution_environment_id || module.input.execution_environment_id >>
+    execution_environment_overrides:
+      security_group: << module.input.ravion_runner_security_group_id >>
+    ravion_runner_role_arn: << module.input.ravion_runner_role_arn >>
+    region: << module.input.aws_region >>
+  inputs:
+    - description: Tag or digest to deploy from the configured image repository. A value starting with "sha256:" is used as a digest, anything else as a tag. Do not pass a full image URI.
+      id: image_ref
+      label: Image tag or digest
+      placeholder: sha256:... or latest
+      required: true
+      type: string
+    - collapsible: true
+      default: << module.input.execution_environment_id >>
+      description: Execution environment the deploy runner launches into to reach the Kubernetes API. Leave empty to use the environment inherited from the EKS cluster, or the default environment of the account that owns the cluster. Its region must match the cluster region.
+      id: execution_environment_id
+      label: Execution environment
+      required: false
+      type: string
+      values: $values:ravion/execution_environments
+  timeout: 1800
+  type: aws:eks
+inputs:
+  - id: section_cluster
+    label: EKS cluster
+    type: section
+  - id: cluster
+    immutable: true
+    label: EKS cluster
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        description: Region of the selected cluster. Must match the region in the cluster ARN, which Ravion cross-checks on every deploy.
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Terraform execution environment inherited from the selected EKS cluster.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_cluster_identity
+        label: Cluster
+        type: section
+      - default: <<ref.stack.output.cluster_name>>
+        id: cluster_name
+        immutable: true
+        label: Cluster name
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_arn>>
+        description: Ravion resolves the owning AWS account and region from this ARN, and rejects a deploy whose cluster name or region disagrees with it.
+        id: cluster_arn
+        immutable: true
+        label: Cluster ARN
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.cluster_endpoint>>
+        description: HTTPS endpoint of the Kubernetes API server. May be private-only; the deploy runner executes inside the cluster VPC.
+        id: cluster_endpoint
+        immutable: true
+        label: Cluster API endpoint
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.cluster_certificate_authority_data>>
+        description: Base64-encoded CA bundle used to verify the API server's TLS certificate. Public key material, not a credential.
+        id: cluster_certificate_authority_data
+        immutable: true
+        label: Cluster certificate authority data
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_role_arn>>
+        description: Stable IAM role the deploy runner assumes to obtain a cluster token. Registered as an EKS access entry by the cluster module.
+        id: ravion_runner_role_arn
+        immutable: true
+        label: Ravion Runner role ARN
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_security_group_id>>
+        description: Security group the deploy runner's network interface joins so it can reach the cluster API endpoint. Null when the cluster module did not create one, which is only workable if the endpoint is public or the execution environment supplies its own group.
+        id: ravion_runner_security_group_id
+        immutable: true
+        label: Ravion Runner security group ID
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.input.vpc_id>>
+        description: VPC the cluster runs in. Load balancer target groups must live in the same VPC as the pods they register.
+        id: vpc_id
+        immutable: true
+        label: VPC ID
+        required: true
+        type: string
+    required: true
+    type: $ref:rvn-eks
+  - description: Add-ons module attached to the cluster above. Selecting it points the Metrics and Logs tabs at whichever observability providers that module has selected.
+    id: section_addons
+    label: EKS add-ons
+    type: section
+  - id: addons
+    label: EKS add-ons
+    mapped_inputs:
+      - collapsible: true
+        default: <<ref.stack.output.amp_workspace_id>>
+        description: Amazon Managed Prometheus workspace the cluster's metrics collector writes to. Inherited from the selected add-ons module; empty until its stack applies with Amazon Managed Prometheus selected.
+        id: amp_workspace_id
+        label: AMP workspace ID
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.amp_region>>
+        description: Region of the Amazon Managed Prometheus workspace. Inherited from the selected add-ons module; empty until its stack applies with Amazon Managed Prometheus selected.
+        id: amp_region
+        label: AMP region
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.logs_rendering_providers>>
+        description: Log stores the Logs tab reads from, in fallback order. Inherited from the selected add-ons module; blank means the in-cluster Loki store.
+        id: logs_rendering_providers
+        label: Logs rendering providers
+        required: false
+        type: string_array
+      - collapsible: true
+    
... diff truncated ...

rvn-eks-web n/a -> 0.4.0

--- remote
+++ compiled
-
+description: Web server on EKS for running an HTTP application behind a shared cluster load balancer, deployed from a container image with no chart of your own.
+name: EKS Web Service
+type: rvn-eks-web

rvn-eks-web n/a -> 0.4.0

--- remote
+++ compiled
+build:
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, cache_from: {tag: "dockerfile"}} : module.input.build_source == "railpack" ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  destinations:
+    - id: ecr
+      repository_arn: << stack.output.ecr_repository_arn >>
+      tags:
+        - <<pipeline.run.id>>-<< module.input.build_source >>
+        - << module.input.build_source >>
+      type: ecr
+  environment_variables: << module.input.build_environment_variables >>
+  infrastructure:
+    ami: << module.input.build_ami || nil >>
+    aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
+    execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
+    instance_size: << module.input.build_instance_size >>
+    permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
+    region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
+    type: << module.input.build_infrastructure_type >>
+  inputs:
+    - description: Defaults to repo default branch
+      id: branch
+      label: Git branch
+      required: false
+      type: string
+    - description: Optional commit SHA, tag, or ref to build. Defaults to the configured branch head.
+      id: ref
+      label: Git ref (commit or tag)
+      required: false
+      type: string
+  source:
+    base_path: << module.input.source_base_path || "." >>
+    branch: << build.input.branch >>
+    ref: << build.input.ref >>
+    repo: << module.input.source_repo >>
+    type: git
+  type: '<< module.input.build_source == "image_registry" ? "disabled" : "image" >>'
+deploy:
+  concurrency:
+    queue_overflow: oldest
+    queue_size: 1
+  definition:
+    create_namespace: "<< module.input.create_namespace != nil ? module.input.create_namespace : true >>"
+    engine: helm
+    namespace: << module.input.namespace >>
+    release_name: << module.input.name >>
+    secrets: "<< module.input.secrets != nil ? module.input.secrets : [] >>"
+    source:
+      branch: main
+      chart: charts/rvn-eks-web
+      ref: rvn-eks-web@0.4.0
+      repo: https://github.com/ravionhq/modules
+      type: inline
+    values:
+      args: "<< module.input.start_command_args != nil ? module.input.start_command_args : [] >>"
+      autoscaling:
+        enabled: << module.input.autoscaling_enabled >>
+        maxReplicas: "<< module.input.max_replicas != nil ? module.input.max_replicas : 3 >>"
+        minReplicas: "<< module.input.min_replicas != nil ? module.input.min_replicas : 1 >>"
+        targetCPUUtilizationPercentage: "<< module.input.autoscaling_cpu_target != nil ? module.input.autoscaling_cpu_target : 70 >>"
+        targetMemoryUtilizationPercentage: << module.input.autoscaling_memory_target >>
+      command: "<< module.input.start_command != nil ? module.input.start_command : [] >>"
+      containerPort: << module.input.container_port >>
+      env: "<< module.input.environment_variables != nil ? module.input.environment_variables : [] >>"
+      fullnameOverride: << module.input.name >>
+      image:
+        digest: '<< deploy.input.image_ref contains "sha256:" ? deploy.input.image_ref : "" >>'
+        repository: '<< module.input.build_source == "image_registry" ? module.input.image_repository : stack.output.ecr_repository_url >>'
+        tag: '<< deploy.input.image_ref contains "sha256:" ? "" : deploy.input.image_ref >>'
+      imagePullSecrets: '<< module.input.image_pull_secret_names != nil ? map(module.input.image_pull_secret_names, ({"name": #})) : [] >>'
+      probes:
+        liveness:
+          enabled: << module.input.liveness_probe_enabled >>
+          initialDelaySeconds: "<< module.input.probe_initial_delay_seconds != nil ? module.input.probe_initial_delay_seconds : 5 >>"
+          path: << module.input.health_check_path >>
+        readiness:
+          enabled: << module.input.readiness_probe_enabled >>
+          initialDelaySeconds: "<< module.input.probe_initial_delay_seconds != nil ? module.input.probe_initial_delay_seconds : 5 >>"
+          path: << module.input.health_check_path >>
+        startup:
+          enabled: << module.input.startup_probe_enabled >>
+          failureThreshold: "<< module.input.startup_probe_failure_threshold != nil ? module.input.startup_probe_failure_threshold : 30 >>"
+          path: << module.input.health_check_path >>
+      replicaCount: "<< module.input.autoscaling_enabled ? (module.input.min_replicas != nil ? module.input.min_replicas : 1) : (module.input.replica_count != nil ? module.input.replica_count : 1) >>"
+      resources:
+        limits: '<< module.input.cpu_limit ? {"cpu": module.input.cpu_limit, "memory": module.input.memory_limit} : {"memory": module.input.memory_limit} >>'
+        requests:
+          cpu: << module.input.cpu_request >>
+          memory: << module.input.memory_request >>
+      service:
+        port: << module.input.container_port >>
+      targetGroupArns:
+        - << stack.output.target_group_arn >>
+      targetGroupBinding:
+        targetType: ip
+        vpcId: << module.input.vpc_id >>
+  infrastructure:
+    cluster_arn: << module.input.cluster_arn >>
+    cluster_certificate_authority_data: << module.input.cluster_certificate_authority_data >>
+    cluster_endpoint: << module.input.cluster_endpoint >>
+    cluster_name: << module.input.cluster_name >>
+    execution_environment_id: << deploy.input.execution_environment_id || module.input.execution_environment_id >>
+    execution_environment_overrides:
+      security_group: << module.input.ravion_runner_security_group_id >>
+    ravion_runner_role_arn: << module.input.ravion_runner_role_arn >>
+    region: << module.input.aws_region >>
+  inputs:
+    - description: Tag or digest to deploy from the configured image repository. A value starting with "sha256:" is used as a digest, anything else as a tag. Do not pass a full image URI.
+      id: image_ref
+      label: Image tag or digest
+      placeholder: sha256:... or latest
+      required: true
+      type: string
+    - collapsible: true
+      default: << module.input.execution_environment_id >>
+      description: Execution environment the deploy runner launches into to reach the Kubernetes API. Leave empty to use the environment inherited from the EKS cluster, or the default environment of the account that owns the cluster. Its region must match the cluster region.
+      id: execution_environment_id
+      label: Execution environment
+      required: false
+      type: string
+      values: $values:ravion/execution_environments
+  timeout: 1800
+  type: aws:eks
+inputs:
+  - id: section_cluster
+    label: EKS cluster
+    type: section
+  - id: cluster
+    immutable: true
+    label: EKS cluster
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        description: Region of the selected cluster. Must match the region in the cluster ARN, which Ravion cross-checks on every deploy.
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Terraform execution environment inherited from the selected EKS cluster.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_cluster_identity
+        label: Cluster
+        type: section
+      - default: <<ref.stack.output.cluster_name>>
+        id: cluster_name
+        immutable: true
+        label: Cluster name
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_arn>>
+        description: Ravion resolves the owning AWS account and region from this ARN, and rejects a deploy whose cluster name or region disagrees with it.
+        id: cluster_arn
+        immutable: true
+        label: Cluster ARN
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.cluster_endpoint>>
+        description: HTTPS endpoint of the Kubernetes API server. May be private-only; the deploy runner executes inside the cluster VPC.
+        id: cluster_endpoint
+        immutable: true
+        label: Cluster API endpoint
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.cluster_certificate_authority_data>>
+        description: Base64-encoded CA bundle used to verify the API server's TLS certificate. Public key material, not a credential.
+        id: cluster_certificate_authority_data
+        immutable: true
+        label: Cluster certificate authority data
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_role_arn>>
+        description: Stable IAM role the deploy runner assumes to obtain a cluster token. Registered as an EKS access entry by the cluster module.
+        id: ravion_runner_role_arn
+        immutable: true
+        label: Ravion Runner role ARN
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_security_group_id>>
+        description: Security group the deploy runner's network interface joins so it can reach the cluster API endpoint. Null when the cluster module did not create one, which is only workable if the endpoint is public or the execution environment supplies its own group.
+        id: ravion_runner_security_group_id
+        immutable: true
+        label: Ravion Runner security group ID
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.input.vpc_id>>
+        description: VPC the cluster runs in. Load balancer target groups must live in the same VPC as the pods they register.
+        id: vpc_id
+        immutable: true
+        label: VPC ID
+        required: true
+        type: string
+    required: true
+    type: $ref:rvn-eks
+  - description: EKS Add-ons module that owns the shared load balancers. Select the add-ons module attached to the cluster above.
+    id: section_load_balancer
+    label: Shared load balancer
+    type: section
+  - id: addons
+    immutable: true
+    label: EKS add-ons
+    mapped_inputs:
+      - default: <<ref.stack.output.public_alb_http_listener_arn>>
+        id: public_alb_http_listener_arn
+        immutable: true
+        label: Public ALB HTTP listener ARN
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.public_alb_https_listener_arn>>
+        description: HTTPS listener ARN from the shared public ALB. Ravion uses it when present, otherwise falls back to HTTP.
+        id: public_alb_https_listener_arn
+        immutable: true
+        label: Public ALB HTTPS listener ARN
+        required: false
+  
... diff truncated ...

rvn-eks-worker n/a -> 0.4.0

--- remote
+++ compiled
-
+description: Background worker on EKS for running a long-lived private process with no exposed port, deployed from a container image with no chart of your own.
+name: EKS Worker
+type: rvn-eks-worker

rvn-eks-worker n/a -> 0.4.0

--- remote
+++ compiled
+build:
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, cache_from: {tag: "dockerfile"}} : module.input.build_source == "railpack" ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  destinations:
+    - id: ecr
+      repository_arn: << stack.output.ecr_repository_arn >>
+      tags:
+        - <<pipeline.run.id>>-<< module.input.build_source >>
+        - << module.input.build_source >>
+      type: ecr
+  environment_variables: << module.input.build_environment_variables >>
+  infrastructure:
+    ami: << module.input.build_ami || nil >>
+    aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
+    execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
+    instance_size: << module.input.build_instance_size >>
+    permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
+    region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
+    type: << module.input.build_infrastructure_type >>
+  inputs:
+    - description: Defaults to repo default branch
+      id: branch
+      label: Git branch
+      required: false
+      type: string
+    - description: Optional commit SHA, tag, or ref to build. Defaults to the configured branch head.
+      id: ref
+      label: Git ref (commit or tag)
+      required: false
+      type: string
+  source:
+    base_path: << module.input.source_base_path || "." >>
+    branch: << build.input.branch >>
+    ref: << build.input.ref >>
+    repo: << module.input.source_repo >>
+    type: git
+  type: '<< module.input.build_source == "image_registry" ? "disabled" : "image" >>'
+deploy:
+  concurrency:
+    queue_overflow: oldest
+    queue_size: 1
+  definition:
+    create_namespace: "<< module.input.create_namespace != nil ? module.input.create_namespace : true >>"
+    engine: helm
+    namespace: << module.input.namespace >>
+    release_name: << module.input.name >>
+    secrets: "<< module.input.secrets != nil ? module.input.secrets : [] >>"
+    source:
+      branch: main
+      chart: charts/rvn-eks-worker
+      ref: rvn-eks-worker@0.4.0
+      repo: https://github.com/ravionhq/modules
+      type: inline
+    values:
+      args: "<< module.input.start_command_args != nil ? module.input.start_command_args : [] >>"
+      autoscaling:
+        enabled: "<< module.input.autoscaling_enabled != nil ? module.input.autoscaling_enabled : false >>"
+        maxReplicas: "<< module.input.max_replicas != nil ? module.input.max_replicas : 3 >>"
+        minReplicas: "<< module.input.min_replicas != nil ? module.input.min_replicas : 1 >>"
+        targetCPUUtilizationPercentage: "<< module.input.autoscaling_cpu_target != nil ? module.input.autoscaling_cpu_target : 70 >>"
+        targetMemoryUtilizationPercentage: << module.input.autoscaling_memory_target >>
+      command: "<< module.input.start_command != nil ? module.input.start_command : [] >>"
+      env: "<< module.input.environment_variables != nil ? module.input.environment_variables : [] >>"
+      fullnameOverride: << module.input.name >>
+      image:
+        digest: '<< deploy.input.image_ref contains "sha256:" ? deploy.input.image_ref : "" >>'
+        repository: '<< module.input.build_source == "image_registry" ? module.input.image_repository : stack.output.ecr_repository_url >>'
+        tag: '<< deploy.input.image_ref contains "sha256:" ? "" : deploy.input.image_ref >>'
+      imagePullSecrets: '<< module.input.image_pull_secret_names != nil ? map(module.input.image_pull_secret_names, ({"name": #})) : [] >>'
+      replicaCount: "<< module.input.autoscaling_enabled ? (module.input.min_replicas != nil ? module.input.min_replicas : 1) : (module.input.replica_count != nil ? module.input.replica_count : 1) >>"
+      resources:
+        limits: '<< module.input.cpu_limit ? {"cpu": module.input.cpu_limit, "memory": module.input.memory_limit} : {"memory": module.input.memory_limit} >>'
+        requests:
+          cpu: << module.input.cpu_request >>
+          memory: << module.input.memory_request >>
+      terminationGracePeriodSeconds: "<< module.input.termination_grace_period_seconds != nil ? module.input.termination_grace_period_seconds : 30 >>"
+  infrastructure:
+    cluster_arn: << module.input.cluster_arn >>
+    cluster_certificate_authority_data: << module.input.cluster_certificate_authority_data >>
+    cluster_endpoint: << module.input.cluster_endpoint >>
+    cluster_name: << module.input.cluster_name >>
+    execution_environment_id: << deploy.input.execution_environment_id || module.input.execution_environment_id >>
+    execution_environment_overrides:
+      security_group: << module.input.ravion_runner_security_group_id >>
+    ravion_runner_role_arn: << module.input.ravion_runner_role_arn >>
+    region: << module.input.aws_region >>
+  inputs:
+    - description: Tag or digest to deploy from the configured image repository. A value starting with "sha256:" is used as a digest, anything else as a tag. Do not pass a full image URI.
+      id: image_ref
+      label: Image tag or digest
+      placeholder: sha256:... or latest
+      required: true
+      type: string
+    - collapsible: true
+      default: << module.input.execution_environment_id >>
+      description: Execution environment the deploy runner launches into to reach the Kubernetes API. Leave empty to use the environment inherited from the EKS cluster, or the default environment of the account that owns the cluster. Its region must match the cluster region.
+      id: execution_environment_id
+      label: Execution environment
+      required: false
+      type: string
+      values: $values:ravion/execution_environments
+  timeout: 1800
+  type: aws:eks
+inputs:
+  - id: section_cluster
+    label: EKS cluster
+    type: section
+  - id: cluster
+    immutable: true
+    label: EKS cluster
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        description: Region of the selected cluster. Must match the region in the cluster ARN, which Ravion cross-checks on every deploy.
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Terraform execution environment inherited from the selected EKS cluster.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_cluster_identity
+        label: Cluster
+        type: section
+      - default: <<ref.stack.output.cluster_name>>
+        id: cluster_name
+        immutable: true
+        label: Cluster name
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_arn>>
+        description: Ravion resolves the owning AWS account and region from this ARN, and rejects a deploy whose cluster name or region disagrees with it.
+        id: cluster_arn
+        immutable: true
+        label: Cluster ARN
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.cluster_endpoint>>
+        description: HTTPS endpoint of the Kubernetes API server. May be private-only; the deploy runner executes inside the cluster VPC.
+        id: cluster_endpoint
+        immutable: true
+        label: Cluster API endpoint
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.cluster_certificate_authority_data>>
+        description: Base64-encoded CA bundle used to verify the API server's TLS certificate. Public key material, not a credential.
+        id: cluster_certificate_authority_data
+        immutable: true
+        label: Cluster certificate authority data
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_role_arn>>
+        description: Stable IAM role the deploy runner assumes to obtain a cluster token. Registered as an EKS access entry by the cluster module.
+        id: ravion_runner_role_arn
+        immutable: true
+        label: Ravion Runner role ARN
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_security_group_id>>
+        description: Security group the deploy runner's network interface joins so it can reach the cluster API endpoint. Null when the cluster module did not create one, which is only workable if the endpoint is public or the execution environment supplies its own group.
+        id: ravion_runner_security_group_id
+        immutable: true
+        label: Ravion Runner security group ID
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.input.vpc_id>>
+        description: VPC the cluster runs in. Load balancer target groups must live in the same VPC as the pods they register.
+        id: vpc_id
+        immutable: true
+        label: VPC ID
+        required: true
+        type: string
+    required: true
+    type: $ref:rvn-eks
+  - description: Add-ons module attached to the cluster above. Selecting it points the Metrics and Logs tabs at whichever observability providers that module has selected.
+    id: section_addons
+    label: EKS add-ons
+    type: section
+  - id: addons
+    label: EKS add-ons
+    mapped_inputs:
+      - collapsible: true
+        default: <<ref.stack.output.amp_workspace_id>>
+        description: Amazon Managed Prometheus workspace the cluster's metrics collector writes to. Inherited from the selected add-ons module; empty until its stack applies with Amazon Managed Prometheus selected.
+        id: amp_workspace_id
+        label: AMP workspace ID
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.amp_region>>
+        description: Region of the Amazon Managed Prometheus workspace. Inherited from the selected add-ons module; empty until its stack applies with Amazon Managed Prometheus selected.
+        id: amp_region
+        label: AMP region
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.logs_rendering_providers>>
+        description: Log stores the Logs tab reads from, in fallback order. Inherited from the selected add-ons module; blank means the in-cluster Loki store.
+        id: logs_rendering_providers
+        label: Logs rendering providers
+        required: false
+        type: string_array
+      - collapsible: true
+        default: <<ref.stack.output.metrics_rendering_providers>>
+        description: Metric stores the Metrics tab reads from, in fallback order. Inherited from the selected add-ons module; blank means Amazon Managed Prometheus.
+        id: metrics_rendering_providers
+        label: Metrics rendering prov
... diff truncated ...

…sion

The chart (0.4.0+) re-emits the running image on upgrade; the module
pins the chart, not the agent. beacon_image_tag is documented as the
one deliberate pin.
The chart now keeps the running agent image across helm upgrades, so an
add-ons apply never moves the agent version, and it carries
httpProxy.credentials for rendering Grafana Cloud and in-cluster
Prometheus through the agent.
… a plain pin

The release no longer ignores changes to `set`. That lifecycle rule, there
since Beacon was added, froze the first image tag ever applied into the
state for good: an instance whose advanced variables once carried
beacon_image_tag=v0.2.0 was rolled back to that image on every upgrade,
and the last two applies wedged on it (helm wait timed out) because the
registry it named no longer holds that tag. A pin is now asserted while
configured and released when removed.

Chart 0.4.1 pins: it preserves the running image whole (registry and
tag) and only for a settled rollout, so a stale image.repository override
cannot make it re-render a tag that registry never held, and a wedged
release takes the floor so a plain re-apply repairs it.
@flybayer
flybayer self-requested a review August 20, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant