feat(gcp-to-aws): add Elastic Beanstalk as migration target for App E… - #101
feat(gcp-to-aws): add Elastic Beanstalk as migration target for App E…#101azpaulp wants to merge 16 commits into
Conversation
…ngine workloads Add AWS Elastic Beanstalk as a PaaS-to-PaaS mapping for Google App Engine resources. App Engine Standard/Flexible now maps to EB by default, with user override to Fargate or Lambda via a new Clarify question (Q7b). Key decisions: - App Engine → EB is a conditional fast-path (deterministic when compute_model is absent or "managed_platform") - Cloud Run remains unconditionally mapped to Fargate (unaffected) - Q7b only fires when App Engine is in inventory - EB design reference provides platform detection, configuration, deployment policies, and App Engine feature mapping - google_app_engine_standard/flexible_app_version added to Skip Mappings Also fixes pre-existing inaccuracies in compute.md examples where Cloud Run and Cloud Functions were incorrectly shown as rubric-evaluated (they're deterministic fast-path mappings).
Fix pre-existing inaccuracies where Cloud Run and Cloud Functions examples showed rubric-based evaluation (inferred) when they actually use deterministic fast-path mappings. Replace the single Output Schema with two examples showing both deterministic and inferred patterns. Also add compute_model to the User Preference criterion description in design-infra.md.
- elastic-beanstalk.md: drop stale version matrix, keep platform names + link to EB supported-platforms docs (versions rot quickly) - reconcile Tomcat as a separate platform from Java SE (Corretto) - correct port guidance: AL2023 proxies to 5000/PORT by default; app must bind the advertised port or first-deploy health checks fail - verify secrets namespace (aws:elasticbeanstalk:application:environmentsecrets) and pin platform cutoff to 2025-03-26 - VPC: ALB in public subnets, instances in private subnets - make sizing consistent (LoadBalanced -> t3.medium+) in EB output schema and compute.md Example 4a - treat google_app_engine_*_app_version as config sources (runtime/ instance_class/scaling), not skips; one EB environment per App Engine service so multi-service apps don't collapse - pricing-cache.md: label EB estimate rows as RDS db.t4g.* (not Aurora)
awslabs#101) Addresses remaining EB review feedback from PR awslabs#101, focused on the App Engine → Elastic Beanstalk mapping (reviewer's main concern). App Engine workload config (runtime, instance_class, scaling, env) lives on the google_app_engine_{standard,flexible}_app_version resources, not the parent google_app_engine_application. The prior pass documented this but the design traversal didn't act on it, so a multi-service app still collapsed into one mapping. - classification-rules.md: reclassify app_version resources from Skip to SECONDARY config sources for the parent's EB mapping - design-infra.md: add an App Engine fan-out step in Pass 1 that scans the full inventory for app_version resources (they link to the parent only by shared project, not by ID, so serves[]/clustering is unreliable), groups by service, and emits one EB environment per service (picking the serving/most-recent version per service) - elastic-beanstalk.md: rework 'config comes from Terraform' section and output schema to a per-service example; drive instance_type from environment type (instance_class / Flexible resources block as a right-sizing nudge only), listing all three scaling blocks - fast-path.md / compute.md: reconcile the notes and examples with the fan-out mechanism; stop showing runtime on the parent resource Verified field names and the parent-linkage behavior against the Terraform Google provider docs. Docs/reference only; no runtime code. mise build tasks pass locally (lint:md, lint:types, lint:frontmatter, test 45/45, fmt:check, bandit, gitleaks); semgrep not installed locally, runs in CI.
|
Thanks for the thorough review, @shinmc — all eight comments are addressed. Summary: EB reference accuracy (verified against the current EB docs, not approximated):
App Engine → EB mapping (comment on
This touched two files beyond the commented lines — Testing: ran the |
Resolves conflicts in clarify.md from PR awslabs#127 (assumption-sheet wizard), which restructured the clarify phase. Re-applied the Q7b (App Engine compute model) additions onto main's new structure: - Category C firing rule + reference-file range (Q7b–Q11) - Q7b row in the Step 3 Disposition Catalog (PROPOSED/N-A) - Q7b early-exit rule (N/A when no App Engine) - compute_model constraint in the example preferences.json - Q7b rows in the Answer Combination Triggers and Defaults tables SKILL.md auto-merged (EB/App Engine additions preserved). All other App Engine → EB work from this branch is unaffected by the merge. Verified: fmt:check, lint:md, lint:types, test (57/57), lint:frontmatter, gitleaks all pass.
Review: feat(gcp-to-aws): add Elastic Beanstalk as migration target for App Engine(Please disregard the earlier bold-rendered review — formatting issue) Overall this is a well-scoped, logically coherent PR. The routing logic is clean, the bug fixes to 1. elastic-beanstalk.md load condition is slightly broader than Q7b fire conditionFile: SKILL.md (conditional reference table) The load condition for elastic-beanstalk.md is:
But Q7b only fires when App Engine is in the inventory. This means if preferences.json carries over from a previous run (or is manually created) with compute_model: "managed_platform" but no App Engine in the current inventory, the EB reference still loads unnecessarily. Low risk, but consider tightening the condition to require App Engine in inventory (the AND case) rather than the OR. 2. Eliminators table: naming asymmetryFile: references/design-refs/compute.md — Eliminators table The new row reads: Every other row in this table uses the GCP service as the source of a failed attempt at the AWS target (e.g., "Cloud Run → Lambda" means "Cloud Run tried to map to Lambda but hit a blocker"). This row is slightly different — the trigger is a user preference rather than a technical constraint. Consider a brief inline note like "(preference override, not technical blocker)" to help readers scan the table consistently. 3. No EB Worker Tier guidanceFile: references/design-refs/elastic-beanstalk.md The heroku-to-aws skill on main explicitly states: "EB Worker tier (SQS-based polling) is NOT used." This PR's elastic-beanstalk.md doesn't address the Worker Tier at all. For App Engine this is fine today (all App Engine services are web-facing), but if the skill later maps background task queues or Cloud Tasks to EB, the omission could lead to the Worker Tier being selected. Consider adding a brief note:
4. Fan-out logic complexity in design-infra.mdFile: references/phases/design/design-infra.md The App Engine fan-out step (item 4 in Pass 1) is the densest paragraph in the file — scanning the entire inventory, matching by shared project, grouping by service, picking serving version, handling missing app_version resources, etc. This is thorough but may be difficult for an LLM to execute reliably in a single pass. Consider:
5. Output Schema section: minor clarity gapFile: references/design-refs/compute.md — Output Schema The deterministic example correctly omits rubric_applied, while the inferred example includes it. This is consistent but implicit. A one-liner above the examples would help:
6. Correctness of existing example fixes (positive note)The corrections to Examples 1 and 2a (Cloud Run and Cloud Functions now shown as deterministic via fast-path rather than inferred via rubric) are accurate and resolve a pre-existing inconsistency with the Direct Mappings table. Good catch. SummaryNo blocking issues. The PR is internally consistent, does not conflict with heroku-to-aws, and the routing logic (Q7b → compute_model → fast-path condition → EB or rubric fallback) is sound. The notes above are improvements for robustness and readability. |
| - **Kubernetes orchestration explicitly required** (`kubernetes = "eks-managed"` or `"eks-or-ecs"` in `preferences.json`) → EKS | ||
| - **Default / no explicit K8s preference** (`kubernetes = "ecs-fargate"` or absent): | ||
| - → **Fargate** (absent kubernetes preference resolves to Fargate, not EKS — teams that want EKS answer A or B in Clarify) | ||
| - If `gcp-resource-inventory.json` contains `google_container_cluster` → EKS (IaC signal shows K8s workload) |
There was a problem hiding this comment.
This new branch defaults GKE to EKS when a cluster is present, but it contradicts with our Clarify phase Q8, which seeks to steer the recommendation to ECS, when the user answers "frustrated with K8s" to that question. In other words we seem to be sending conflicting signals to LLM with this recommendation
There was a problem hiding this comment.
Agree with this. The new GKE guidance fights what Clarify Q8 is trying to do.
On main, if the user picks Fargate (or doesn’t say they want Kubernetes), we map GKE to Fargate. This PR changes that so “there’s a GKE cluster in the inventory” alone pushes the mapping to EKS — even when the user just said they’re frustrated with K8s and want Fargate.
There’s also a contradiction in the same file: the rubric still says “don’t default to EKS,” but the new Signals bullet does exactly that when a cluster is present.
I’d revert that bullet back to main’s Fargate default, and only recommend EKS when the user explicitly asks for it in Q8 (or when multi-cloud already forces EKS).
There was a problem hiding this comment.
Resolved in the latest push. Reverted the google_container_cluster → EKS bullet back to the Fargate default; an absent/ecs-fargate Kubernetes preference now resolves to Fargate (EKS only when the user explicitly asks via Q8 A/B), so it no longer contradicts Q8's "frustrated with K8s → Fargate" steer. The file's 6-criteria rubric ("absent → Fargate, do not default to EKS") and the GKE Signals bullet now agree. Thanks for catching this. It was an out-of-scope regression in the EB branch.
|
Question on intended audience, from the author of #149 (gcloud live discovery): are TF-less App Engine shops in scope for this mapping? As written, #101 is IaC-path work — the App Engine → EB fast-path triggers off resources classified from Terraform (
So the question decides the follow-up:
Either answer is fine — mainly making sure the gap between the two PRs is a decision rather than an accident. |
Revert an out-of-scope GKE routing regression and apply reviewer polish (herosjourney, icarthick). - compute.md: revert the GKE Signals bullet to main's Fargate default — a google_container_cluster in inventory no longer forces EKS over the user's Fargate/Q8 preference (flagged by two reviewers; also contradicted the file's own 6-criteria rubric). Add 'preference override, not a technical blocker' note to the App Engine Eliminators row; add a one-line note that deterministic mappings omit rubric_applied. - elastic-beanstalk.md: add 'Discovery Inputs' section clarifying Terraform (full per-service EB) vs billing (coarse) vs app-code/gcloud-live (not yet wired — awslabs#149 follow-up); add Worker-tier note (skill uses WebServer tier only, aligning with heroku-to-aws). - design-billing.md: App Engine billing row Fargate -> Elastic Beanstalk so the billing path matches the new default. - design-infra.md: convert the App Engine fan-out step from a dense paragraph to an ordered sub-step list for reliable single-pass execution. - SKILL.md: tighten elastic-beanstalk.md load condition — require App Engine in inventory; skip even if compute_model is set. Verified: fmt:check, lint:md, lint:types, test 57/57, lint:frontmatter, gitleaks all pass.
…k-gcp # Conflicts: # migrate/plugins/migration-to-aws/skills/gcp-to-aws/SKILL.md # migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/design-refs/compute.md # migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/clarify/clarify.md
|
Thanks for the excellent feedback! I am preparing an update to this PR to address it. |
…e + sizing) Third-round PR awslabs#101 review response. Makes the App Engine → Elastic Beanstalk feature complete across all phases and resolves the reviewer blockers. Design/routing: - Replace the Q6-availability EB sizing rule with source-config sizing (the repo's established pattern): environment type + instance size derive per-service from the app_version's own scaling block and instance_class (Standard) / resources block (Flexible). Q6 governs databases only. - Fix the preferred-target reversal: the PaaS/managed-platform row is gated on compute_model (absent/managed_platform); Q7b=B/C keeps its rubric-selected Fargate/Lambda target (explicit enforcement exemption). - Per-service unique gcp_address (parent TF address # service); carry min_instances + max_instances through design→generate. Estimate: - Add an Elastic Beanstalk cost row (EC2 × min_instances × 730 + ALB when LoadBalanced; /bin/zsh service fee), EB log-volume heuristic, and EB EC2 in the Graviton rollup. ALB row carves out LoadBalanced EB envs to avoid double-counting. Generate: - Route EB to compute.tf; emit aws_elastic_beanstalk_application + _environment with setting blocks (InstanceType, EnvironmentType, LoadBalancerType=application for ALB, ASG Min/MaxSize, IAM instance profile, VPC — public subnet for SingleInstance, private+ALB for LoadBalanced, env vars). Resolve solution_stack_name at generate time (do not paste the label). - Migration script: shared always-emitted preamble + independent ECR and EB source-deploy sections (EB builds from Dockerfile at deploy time — no ECR push); reconcile the IaC model (Terraform provisions, CLI deploys). Discovery: capture App Engine version fields (service, runtime, instance_class, scaling, serving_status, project, env_variables) into the inventory. Verified: fmt:check, lint:md (0), lint:types, test 57/57, lint:frontmatter, gitleaks all pass. Reviewed across two adversarial passes; both BLOCKERs and six follow-on findings resolved.
|
Pushed an update that takes App Engine → Elastic Beanstalk from a design-phase mapping to a complete end-to-end feature, and addresses the follow-on review feedback. What prompted the expansion: review surfaced that EB was only wired into Design — an App Engine → EB migration would have produced no cost line and no Terraform. Rather than ship a design-only feature, this wires EB through the same phases every other compute target uses. Design / routing
Estimate — added an EB cost row (EC2 × min_instances × 730 + ALB when LoadBalanced; $0 service fee), EB log-volume, EB in the Graviton rollup, and an ALB double-count carve-out (EB manages its own LB). Generate — EB → Discover — captures the App Engine version fields (service, runtime, instance_class, scaling, serving_status, project, env_variables) the mapping needs. Scope: this spans discover→clarify→design→estimate→generate — it's one coherent feature (see the updated description for the per-phase rationale). TF-less App Engine (gcloud/app-code-only) remains a #149 follow-up, documented in the "Discovery Inputs" note. Cross-skill note (heroku-to-aws): heroku's EB path still omits Testing: |
|
TL;DR requesting one logic fix and a rebase before merge: Fix: make Q7b respect Q5. Q5 asks "do you need multi-cloud portability?": if yes, the plugin routes all compute to portable EKS. Q7b (new in this PR) asks "what compute model for your App Engine apps?" and defaults to Elastic Beanstalk: the most AWS-locked-in option. The PR never connects them: a user who answered "yes, portable" on Q5 still gets EB by default from Q7b. Fix: when Q5 = multi-cloud, Q7b should not fire (App Engine follows the container path to EKS), same as Q8 already does. Rebase: GitHub reports conflicts; clarify.md was rewritten (#170/#171) since this branch, so Q7b needs re-checking against the new sheet/batching rules, not just a textual merge. |
…k-gcp # Conflicts: # migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/clarify/clarify.md
When Q5 = multi-cloud portability, Q5 already records `compute: "eks"`, but Q7b still defaulted App Engine → Elastic Beanstalk (the most AWS-locked-in target). The two signals were never connected — same conflicting-signal class as the earlier GKE/Q8 issue. Mirror Q8's existing multi-cloud early-exit for Q7b, end to end: Clarify: - Q7b fires only when App Engine present AND Q5 != multi-cloud; N/A otherwise. - Early-Exit + sheet-correction rules route App Engine → EKS under multi-cloud, overriding the EB default. Disposition catalog, defaults table, and answer- combination triggers updated to match. Design: - fast-path Direct Mapping + PaaS Preferred-Target rows gated on `compute` != "eks"; new enforcement exemption mirrors the compute_model one. - compute.md rubric: `compute: "eks"` is a criterion-1 hard override (selects EKS and stops before the managed-platform/EB branch — fixes first-match-wins ordering that would otherwise pick EB/Fargate first). Example 4c added. - design-infra Pass 1 condition, App Engine fan-out suppression, and Preferred- target check updated; app_version resources skipped like any non-EB path (no pipeline STOP, no double-warning). - design-billing path: App Engine → EKS override applies in billing-only mode too (compute:eks is a top-level constraint, not a config detail). - index.md / elastic-beanstalk.md / SKILL.md load-conditions updated. Verified: fmt:check, lint:md, lint:types, test, lint:frontmatter, shared:check, fixtures:check, fixtures:assert, gitleaks all green. Adversarial review pass confirmed routing is STOP-safe and key discipline (compute vs compute_model vs kubernetes) is clean.
The App Engine billing-heuristic row put the `compute: "eks"` multi-cloud override note under the column headed "Alternatives (chosen by IaC path)", which read as if EKS only applied on the IaC path — an LLM reading the row alone would route a multi-cloud App Engine billing migration to Elastic Beanstalk. Point the row explicitly at the multi-cloud override prose directly below the table (which already applies the override on the billing path), removing the contradiction without changing behavior.
|
Thank you @herosjourney! I've pushed an update to address your last comment. Please let me know if there's anything else I can do for this PR. I do intend to issue a follow-up to address nits and small improvements. |
…ngine workloads
Problem
Add AWS Elastic Beanstalk as a PaaS-to-PaaS mapping for Google App Engine resources. App Engine Standard/Flexible maps to EB by default, with user override to Fargate or Lambda via a new Clarify question (Q7b). Because EB is a first-class compute target, it is wired through every phase the other compute targets use — discover → clarify → design → estimate → generate — so a migration produces a complete design, cost estimate, and Terraform, not just a mapping.
Solution
Routing (Clarify + Design)
compute_modelis absent or"managed_platform"); Q7b = container_orchestration → Fargate, serverless → Lambda. Q7b fires only when App Engine is in inventory.compute_model, so an explicit Q7b = B/C choice is never silently reversed back to EB.compute_modeldoes not touch it.compute: "eks"is recorded, Q7b does not fire, and App Engine routes to EKS — overriding both the EB default and the container-path Fargate. This mirrors the existing Q8/GKE multi-cloud early-exit, so the two portability signals can no longer disagree. Applies on both the IaC and billing design paths.Per-service fan-out (Design)
runtime,instance_class, scaling,env_variables) lives on thegoogle_app_engine_standard/flexible_app_versionresources, not the parent. The design fan-out emits one EB environment per App Engine service (grouping a service's versions), sized from that service's own scaling block + instance_class (the repo's "size from the source resource" pattern — Q6 availability governs databases only).*_app_versionresources are config sources (Skip Mappings — read for config, not emitted as standalone AWS resources).Estimate
Generate
compute.tf; emitsaws_elastic_beanstalk_application+aws_elastic_beanstalk_environment(instance profile,LoadBalancerType=application,data-source solution stack, VPC placement — private+ALB for LoadBalanced, public subnet for SingleInstance).Discover
service,runtime,instance_class, scaling,serving_status,project,env_variables) into the inventory.Scope note: TF-less App Engine (gcloud/app-code-only discovery) is a #149 follow-up; the "Discovery Inputs" note in
elastic-beanstalk.mddocuments which discovery paths produce a full vs. coarse vs. no EB mapping today. This branch is merged up to currentorigin/main(including the #170/#171 Clarify interaction-contract rewrite).Also fixes pre-existing inaccuracies in compute.md examples where Cloud Run and Cloud Functions were incorrectly shown as rubric-evaluated (they're deterministic fast-path mappings).
Type of Change
Team Folder
advisor/migrate/Checklist
mise run buildlocally and it passes