Download index.html from getreadystack/valkey-migration-check: direct link, hf CLI and curl.
- Browser
- Download file 44.2 kB
-
https://huggingface.co/spaces/getreadystack/valkey-migration-check/resolve/main/index.html
- Command line
-
hf download hf://spaces/getreadystack/valkey-migration-check/index.html
-
curl -L -o index.html https://huggingface.co/spaces/getreadystack/valkey-migration-check/resolve/main/index.html
44.2 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>ElastiCache Valkey Migration — check redis settings for valkey</title> | |
| <meta name="description" content="This free browser tool checks infrastructure files for ElastiCache Redis versions, parameter groups, and redis:7.4+ images."> | |
| <style> | |
| :root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512} | |
| .wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px} | |
| textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box} | |
| .bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer} | |
| input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px} | |
| table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65} | |
| .sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600} | |
| .note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa} | |
| </style> | |
| <script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script> | |
| <!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/valkey-migration-check"><style data-yj-mfit="1">#out{max-width:100%}#out td,#out th{overflow-wrap:anywhere}#out pre,#out code{white-space:pre-wrap;overflow-wrap:anywhere}@media (max-width:640px){table{display:block;max-width:100%;overflow-x:auto}pre{max-width:100%;overflow-x:auto}code,a{overflow-wrap:anywhere}img,svg,video,canvas,iframe{max-width:100%}textarea,input,select{max-width:100%;box-sizing:border-box}.yj-lgbar{position:static;justify-content:flex-end;margin:0 0 10px}h1,h2,h3,h4,p,li,dd,dt,blockquote,figcaption,summary,label,.res,.lead{overflow-wrap:anywhere}label{max-width:100%;box-sizing:border-box}#out table:not(:has(tr>:nth-child(4))){display:table;table-layout:fixed;width:100%}#out table:has(tr>:nth-child(4)),#out table:has(tr>:nth-child(4)) tbody,#out table:has(tr>:nth-child(4)) tr,#out table:has(tr>:nth-child(4)) td{display:block;width:auto;overflow:visible}#out table:has(tr>:nth-child(4)) thead{display:none}#out table:has(tr>:nth-child(4)) tr{padding:10px 0;border-bottom:1px solid rgba(128,128,128,.28)}#out table:has(tr>:nth-child(4)) td{border:0;padding:1px 0}#out table:has(tr>:nth-child(4)) td:nth-child(-n+3){display:inline-block;margin-right:10px;font-size:12px;opacity:.78}}</style> | |
| </head> | |
| <body> | |
| <div class="wrap"> | |
| <h1>ElastiCache Valkey Migration — check redis settings for valkey</h1> | |
| <p class="lede">Valkey migration check: flags ElastiCache Redis OSS 4/5/6 engine versions (Extended Support billing), redis parameter-group families and redis:7.4+ images in Terraform, CloudFormation, compose and Dockerfiles. Runs entirely in your browser — nothing is uploaded.</p> | |
| <textarea id="src" spellcheck="false"># main.tf — sessions, rate limits, jobs and page cache on AWS ElastiCache | |
| resource "aws_elasticache_parameter_group" "sessions" { | |
| name = "sessions-params" | |
| family = "redis5.0" | |
| } | |
| resource "aws_elasticache_replication_group" "sessions" { | |
| replication_group_id = "sessions" | |
| description = "user sessions" | |
| engine = "redis" | |
| engine_version = "5.0.6" | |
| node_type = "cache.m5.large" | |
| num_cache_clusters = 2 | |
| parameter_group_name = aws_elasticache_parameter_group.sessions.name | |
| } | |
| resource "aws_elasticache_cluster" "rate_limit" { | |
| cluster_id = "rate-limit" | |
| engine = "redis" | |
| engine_version = "4.0.10" | |
| node_type = "cache.t3.small" | |
| num_cache_nodes = 1 | |
| } | |
| resource "aws_elasticache_cluster" "jobs" { | |
| cluster_id = "jobs" | |
| engine = "redis" | |
| engine_version = "6.2" | |
| node_type = "cache.r6g.large" | |
| num_cache_nodes = 1 | |
| } | |
| resource "aws_elasticache_serverless_cache" "pages" { | |
| name = "pages" | |
| engine = "redis" | |
| } | |
| resource "aws_ecs_task_definition" "worker" { | |
| family = "worker" | |
| container_definitions = jsonencode([{ | |
| name = "sidecar-cache" | |
| image = "redis:7.4-alpine" | |
| }]) | |
| }</textarea> | |
| <div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div> | |
| <div id="out" aria-live="polite"></div> | |
| <div id="paid"><strong>Free here:</strong> Check the open main.tf, CloudFormation template, compose.yaml or Dockerfile for Redis ties, with the Valkey fix on each line. <strong>In the editor:</strong> Scan every repo in the workspace in one pass and export a dated Markdown migration plan per repo with each Redis tie mapped to its Valkey line — that part asks for a licence key. <a href="https://getreadystack.com/api/buy/cl/polar_cl_FdHdA1K6PeelujKUjhH82L91vARLJU65PFD1602Uq9C">Get the full version — $29</a> · $29 once · one licence key per person or team seat. AWS example: Extended Support adds $0.1248/hr per cache.m5.large node.</div> | |
| <p class="note">Same engine as the VS Code extension, byte for byte.</p> | |
| </div> | |
| <script>var VK_RULES = [ | |
| {"id": "VK01", "check": "elasticache-redis-oss-4-5", "sev": "error", "kind": "ec-version", "majors": [4, 5], | |
| "std_end": "2026-01-31", "y1": "2026-02-01", "y3": "2028-02-01", "ext_end": "2029-01-31", | |
| "msg": "ElastiCache Redis OSS {v} left standard support on January 31, 2026. Since February 1, 2026 each node is billed Extended Support: an 80% premium on the on-demand node price in years 1-2, 160% from February 1, 2028; after January 31, 2029 AWS upgrades it to Valkey itself.", | |
| "fix": "engine = \"valkey\" · engine_version = \"8.0\"", | |
| "source": "https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/extended-support-versions.html"}, | |
| {"id": "VK02", "check": "elasticache-redis-oss-6", "sev": "warn", "kind": "ec-version", "majors": [6], | |
| "std_end": "2027-01-31", "y1": "2027-02-01", "y3": "2029-02-01", "ext_end": "2030-01-31", | |
| "msg": "ElastiCache Redis OSS {v} leaves standard support on January 31, 2027. From February 1, 2027 each node is billed Extended Support (80% premium in years 1-2, 160% from February 1, 2029). Moving to Valkey now avoids it.", | |
| "fix": "engine = \"valkey\" · engine_version = \"8.0\"", | |
| "source": "https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/extended-support-versions.html"}, | |
| {"id": "VK03", "check": "redis-4-5-parameter-group", "sev": "error", "kind": "family", "majors": [4, 5], | |
| "msg": "A redis{v} parameter group only attaches to a Redis OSS {m} cache, so it holds the cache on a version billed Extended Support since February 1, 2026. Create a valkey8 parameter group and point the cache at it in the same change.", | |
| "fix": "family = \"valkey8\"", | |
| "source": "https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/ParameterGroups.Engine.html"}, | |
| {"id": "VK04", "check": "redis-6-7-parameter-group", "sev": "warn", "kind": "family", "majors": [6, 7], | |
| "msg": "A redis{v} parameter group ties the cache to the Redis OSS engine. Switching the engine to Valkey needs a valkey8 (or valkey7) parameter group; the redis family cannot be reused.", | |
| "fix": "family = \"valkey8\"", | |
| "source": "https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/ParameterGroups.Engine.html"}, | |
| {"id": "VK05", "check": "serverless-cache-on-redis", "sev": "warn", "kind": "ec-serverless", | |
| "msg": "This ElastiCache Serverless cache runs the redis engine. AWS prices ElastiCache Serverless for Valkey 33% lower than the other supported engines.", | |
| "fix": "engine = \"valkey\"", | |
| "source": "https://aws.amazon.com/elasticache/pricing/"}, | |
| {"id": "VK06", "check": "node-cache-on-redis-7", "sev": "warn", "kind": "ec-node-current", | |
| "msg": "This node-based ElastiCache cache runs the redis engine ({v}). AWS prices node-based ElastiCache for Valkey 20% lower than the other supported engines.", | |
| "fix": "engine = \"valkey\" · engine_version = \"8.0\"", | |
| "source": "https://aws.amazon.com/elasticache/pricing/"}, | |
| {"id": "VK07", "check": "redis-image-source-available", "sev": "warn", "kind": "image", | |
| "msg": "Image {img} is Redis 7.4 or later, which ships under RSALv2/SSPLv1 (Redis 8 adds AGPLv3), not the BSD-3 licence of Redis 7.2 and earlier. Valkey, the Linux Foundation fork of Redis 7.2.4, stays BSD-3 and speaks the same protocol.", | |
| "fix": "image: valkey/valkey:8", | |
| "source": "https://redis.io/legal/licenses/"}, | |
| {"id": "VK08", "check": "redis-stack-image", "sev": "warn", "kind": "regex", | |
| "re": "(?:^|[\\s\"'=:/])redis/redis-stack(?:-server)?\\b", "flags": "", | |
| "msg": "redis/redis-stack bundles the Redis modules (search, JSON, bloom), which were never BSD-licensed. Valkey ships its own valkey-json, valkey-bloom and valkey-search modules; check each command you use before swapping.", | |
| "fix": "image: valkey/valkey-bundle", | |
| "source": "https://valkey.io/"} | |
| ] | |
| ;</script> | |
| <script>// Valkey Migration Check engine: finds Redis ties in Terraform, CloudFormation, compose and Dockerfiles. | |
| // Same file runs in Node (VS Code extension, verify) and in the browser (free web page). | |
| (function (root) { | |
| const RULES = (typeof module !== 'undefined') ? require('./rules.json') : root.VK_RULES; | |
| const byKind = k => RULES.filter(r => r.kind === k); | |
| const BLOCK_START = [ | |
| /^\s*resource\s+"(\w+)"\s+"[\w-]+"/, // Terraform | |
| /^ {2}([A-Za-z0-9]+):\s*(?:#.*)?$/ // CloudFormation / compose top-level entry | |
| ]; | |
| const EC_NODE = /aws_elasticache_(?:cluster|replication_group)\b|AWS::ElastiCache::(?:CacheCluster|ReplicationGroup)\b/; | |
| const EC_SERVERLESS = /aws_elasticache_serverless_cache\b|AWS::ElastiCache::ServerlessCache\b/; | |
| const ENGINE = /^\s*(?:engine\s*=|"?Engine"?\s*:)\s*["']?([\w-]+)/; | |
| const VERSION = /^\s*(?:engine_version\s*=|"?EngineVersion"?\s*:)\s*["']?(\d+)(?:\.[\dx]+)*/; | |
| const FAMILY = /(?:\bfamily\s*=|\bCacheParameterGroupFamily\s*:|\bparameter_group_name\s*=|\bCacheParameterGroupName\s*:)\s*["']?(?:default\.)?redis(\d)(\.\d|\.x)?/; | |
| const IMAGE = /(?:^\s*(?:-\s*)?image\s*[:=]\s*|^\s*FROM\s+(?:--platform=\S+\s+)?|"image"\s*:\s*)["']?((?:docker\.io\/)?(?:library\/)?redis)(?::([\w.-]+))?["']?(?:\s|$|#|,)/i; | |
| function fill(s, vars) { return s.replace(/\{(\w+)\}/g, (_, k) => vars[k] != null ? vars[k] : ''); } | |
| function push(out, r, line, lines, vars, sev) { | |
| out.push({ check: r.check, id: r.id, sev: sev || r.sev, msg: fill(r.msg, vars), fix: r.fix, source: r.source, line: line + 1, text: lines[line].trim() }); | |
| } | |
| // Licence of the tag: Redis 7.4+ and 8+ are source-available; latest/unpinned/7 resolve to those. | |
| function licensedTag(tag) { | |
| if (!tag || /^(latest|alpine|bookworm|trixie)/i.test(tag)) return true; | |
| const m = tag.match(/^(\d+)(?:\.(\d+))?/); | |
| if (!m) return false; | |
| const maj = +m[1], min = m[2] == null ? null : +m[2]; | |
| return maj >= 8 || (maj === 7 && (min == null || min >= 4)); | |
| } | |
| function blocks(lines) { | |
| const out = []; | |
| let cur = null; | |
| lines.forEach((l, i) => { | |
| if (/^\s*(#|\/\/)/.test(l)) return; | |
| const m = BLOCK_START.map(rx => l.match(rx)).find(Boolean); | |
| if (m) { cur = { start: i, head: l, body: [] }; out.push(cur); } | |
| if (cur) cur.body.push(i); | |
| }); | |
| return out; | |
| } | |
| function check(text, opts) { | |
| const today = (opts && opts.today) || new Date().toISOString().slice(0, 10); | |
| const lines = String(text || '').split(/\r?\n/); | |
| const findings = []; | |
| for (const b of blocks(lines)) { | |
| const txt = b.body.map(i => lines[i]).join('\n'); | |
| const node = EC_NODE.test(txt), serverless = EC_SERVERLESS.test(txt); | |
| if (!node && !serverless) continue; | |
| let engine = 'redis', engineLine = b.start, verLine = -1, major = null, verText = ''; | |
| for (const i of b.body) { | |
| const e = lines[i].match(ENGINE); if (e) { engine = e[1].toLowerCase(); engineLine = i; } | |
| const v = lines[i].match(VERSION); if (v) { verLine = i; major = +v[1]; verText = (lines[i].match(/(\d+(?:\.[\dx]+)*)/) || [])[1]; } | |
| } | |
| if (engine !== 'redis') continue; | |
| if (serverless) { byKind('ec-serverless').forEach(r => push(findings, r, engineLine, lines, {})); continue; } | |
| const verRule = byKind('ec-version').find(r => r.majors.includes(major)); | |
| if (verRule) { | |
| const vars = { v: verText }; | |
| let sev = verRule.sev; | |
| if (today >= verRule.y1) sev = 'error'; | |
| const f = push(findings, verRule, verLine, lines, vars, sev); | |
| const last = findings[findings.length - 1]; | |
| if (today > verRule.ext_end) last.msg += ' Extended Support has ended for this version.'; | |
| else if (today >= verRule.y3) last.msg += ' As of ' + today + ' the premium is 160%.'; | |
| else if (today >= verRule.y1) last.msg += ' As of ' + today + ' this node is billed the 80% premium.'; | |
| } else { | |
| byKind('ec-node-current').forEach(r => push(findings, r, engineLine, lines, { v: verText ? 'Redis OSS ' + verText : 'version not pinned' })); | |
| } | |
| } | |
| lines.forEach((line, i) => { | |
| if (/^\s*(#|\/\/)/.test(line)) return; | |
| const fam = line.match(FAMILY); | |
| if (fam) { | |
| const maj = +fam[1]; | |
| const r = byKind('family').find(x => x.majors.includes(maj)); | |
| if (r) push(findings, r, i, lines, { v: maj + (fam[2] || ''), m: maj }); | |
| } | |
| const img = line.match(IMAGE); | |
| if (img && licensedTag(img[2])) byKind('image').forEach(r => push(findings, r, i, lines, { img: img[1] + (img[2] ? ':' + img[2] : '') })); | |
| byKind('regex').forEach(r => { if (new RegExp(r.re, r.flags || '').test(line)) push(findings, r, i, lines, {}); }); | |
| }); | |
| findings.sort((a, b) => a.line - b.line); | |
| return { findings, errors: findings.filter(f => f.sev === 'error').length, warnings: findings.filter(f => f.sev === 'warn').length, as_of: today }; | |
| } | |
| const api = { engine: { check }, RULES, RULE_COUNT: RULES.length }; | |
| if (typeof module !== 'undefined') module.exports = api; | |
| root.VKENGINE = api; | |
| })(typeof window !== 'undefined' ? window : globalThis); | |
| </script> | |
| <script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다. | |
| ; | |
| function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); } | |
| function summaryLine(res) { | |
| const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length; | |
| return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.'; | |
| } | |
| function toText(res, label) { | |
| const f = (res && res.findings) || []; | |
| const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)]; | |
| f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); }); | |
| return lines.join('\n'); | |
| } | |
| function toHtml(res) { | |
| const f = (res && res.findings) || []; | |
| if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>'; | |
| const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join(''); | |
| return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>'; | |
| } | |
| var VKREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml }; | |
| if (typeof module !== 'undefined' && module.exports) module.exports = VKREPORT; | |
| else window.VKREPORT = VKREPORT; | |
| </script> | |
| <script> | |
| (function(){ | |
| var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today'); | |
| today.value=new Date().toISOString().slice(0,10); | |
| function run(){ try { var res=window.VKENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.VKREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } } | |
| go.onclick=run; if (src.value.trim()) run(); | |
| })(); | |
| </script> | |
| <section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://open-vsx.org/extension/readystack/valkey-migration-check" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'valkey-migration-check',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/team" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section> | |
| <section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind Valkey Migration Check — ElastiCache Redis ties every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"valkey-migration-check",lang:"en",source:"rule_alert"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);document.addEventListener("click",function(ev){var b=ev.target&&ev.target.closest?ev.target.closest("button,input[type=submit]"):null;if(b&&!b.closest("[data-yj],[data-yj-cta],[data-yj-install],[data-yj-alert],.yj-find,.yj-related,#yj-ask,.yjp"))mv(ev);},true);})();</script></section> | |
| <section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the full version <span class="yj-price">$29</span></h2><p class="yj-cta-paid" style="margin:.25rem 0 .6rem;color:#1f2a37">Scan every repo in the workspace in one pass and export a dated Markdown migration plan per repo, each Redis tie mapped to its Valkey line</p><p class="yj-cta-pay" style="margin:.25rem 0 1rem;color:#5b6b7c;font-size:.94rem">One payment, one licence key for this tool. The key is shown right after payment.</p><p class="yj-cta-anchor" style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">AWS's own example: a cache.m5.large node on Redis OSS 5 in US East (Ohio) is $0.156/hr on demand and Extended Support adds $0.1248/hr (80%) in years 1-2; AWS prices node-based ElastiCache for Valkey 20% lower and ElastiCache Serve</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_FdHdA1K6PeelujKUjhH82L91vARLJU65PFD1602Uq9C" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section> | |
| <!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script> | |
| <script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script> | |
| <script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-30">Updated 2026-09-30</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-30","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku424870_result_card.jpg" alt="Migrate from Redis to Valkey on ElastiCache: the six Terraform lines that keep you on Redis" loading="lazy" style="max-width:100%;border-radius:6px"></p> | |
| <p>Six Redis ties turned up in a 44-line main.tf that a platform engineer running AWS ElastiCache checked before moving to Valkey: three errors and three warnings, on six different lines, and two of the caches were already paying an 80% Extended Support premium.</p> | |
| <h3>What AWS changed, and when</h3> | |
| <p>AWS ended standard support for ElastiCache Redis OSS versions 4 and 5 on January 31, 2026. Since February 1, 2026, every cache still on those versions is enrolled in Extended Support automatically and billed for it: an 80% premium on the on-demand node price in years one and two, and 160% from February 1, 2028. After January 31, 2029, AWS upgrades the remaining caches to Valkey itself. Redis OSS 6 follows one year later: standard support ends January 31, 2027, and the charge starts February 1, 2027.</p> | |
| <p>AWS's own example puts a number on it. A cache.m5.large node on Redis OSS 5 in US East (Ohio) costs $0.156 an hour on demand; Extended Support adds $0.1248 an hour. Reserved-node discounts do not apply to that surcharge. At the same time AWS prices node-based ElastiCache for Valkey 20% lower, and ElastiCache Serverless for Valkey 33% lower, than the other engines.</p> | |
| <h3>The six lines</h3> | |
| <table><thead><tr><th>Line</th><th>Redis line</th><th>Valkey fix</th></tr></thead><tbody><tr><td>4</td><td>family = "redis5.0"</td><td>family = "valkey8"</td></tr><tr><td>11</td><td>engine_version = "5.0.6"</td><td>engine = "valkey", engine_version = "8.0"</td></tr><tr><td>20</td><td>engine_version = "4.0.10"</td><td>engine = "valkey", engine_version = "8.0"</td></tr><tr><td>28</td><td>engine_version = "6.2"</td><td>engine = "valkey", engine_version = "8.0"</td></tr><tr><td>35</td><td>engine = "redis" (serverless)</td><td>engine = "valkey"</td></tr><tr><td>42</td><td>image = "redis:7.4-alpine"</td><td>image = "valkey/valkey:8-alpine"</td></tr></tbody></table> | |
| <p>The three errors are the two caches on Redis OSS 4.0.10 and 5.0.6, which are billed today, and the redis5.0 parameter group. That one is easy to miss: a parameter group family belongs to one engine version, so a cache cannot switch engines while it still points at redis5.0. The three warnings are the Redis OSS 6.2 cache (an error from February 1, 2027), the serverless cache on the redis engine, and an ECS sidecar pulling redis:7.4-alpine. Redis 7.4 and later ship under RSALv2 and SSPLv1 (Redis 8 adds AGPLv3) instead of the BSD-3 licence of Redis 7.2; Valkey, the Linux Foundation fork of Redis 7.2.4, stays BSD-3.</p> | |
| <h3>Why the console is not enough</h3> | |
| <p>The ElastiCache console lists what is running, not the Terraform line that pins it. A chatbot will rewrite the file you paste, but it does not know the Extended Support dates and usually leaves the parameter group alone.</p> | |
| <h3>Checking every line at once</h3> | |
| <p>Valkey Migration Check reads Terraform, CloudFormation, compose, Kubernetes YAML and Dockerfiles against 8 rules: Redis OSS 4 and 5 engine versions, Redis OSS 6 engine versions, redis4.0 and redis5.0 parameter groups, redis6.x and redis7 parameter groups, serverless caches on redis, node caches on redis 7, redis:7.4+ images and redis/redis-stack images. Each finding names the line, the Valkey replacement and the source page. The fixed main.tf returns 0 findings.</p> | |
| <p>The as-of date changes the answer. Set it to February 1, 2027 and the Redis OSS 6 warning becomes an error; set it to February 1, 2028 and the Redis OSS 4 and 5 findings name the 160% premium.</p> | |
| <p>Start with the caches already billed, then move Redis OSS 6 before February 1, 2027.</p> | |
| <p>The single-file check is free in VS Code and on the web page, with every rule and every fix. The paid version scans every repo in a workspace and exports a dated Markdown migration plan per repo.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku424870_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku424870_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does Valkey Migration Check do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Valkey Migration Check reads Terraform, CloudFormation, compose, Kubernetes and Dockerfiles and flags each line that ties a project to Redis: ElastiCache Redis OSS 4, 5 and 6 engine versions, redis parameter group families, serverless and node caches on the redis engine, and redis:7.4 or later images. Each finding shows the Valkey replacement line and the AWS or Redis source.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is Valkey Migration Check for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It is for platform engineers and DevOps leads who run Redis on AWS ElastiCache through Terraform or CloudFormation. ElastiCache Redis OSS 4 and 5 caches have been billed an 80% Extended Support premium since February 1, 2026, and Redis OSS 6 caches follow on February 1, 2027. It also suits teams leaving Redis 7.4 images over the licence change.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not ask a chatbot or read the AWS console?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">The ElastiCache console lists running caches, not the Terraform line that pins each version, so the next apply can recreate a Redis OSS 5 cache. A chatbot rewrites the file you paste but does not know the Extended Support dates, and it often keeps the redis5.0 parameter group, which blocks the engine switch.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what does the paid version add?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">The free version runs all 8 rules on the open file in VS Code and on the web page, with the Valkey fix on every finding and no cap. The paid version, $29 once with one licence key per person or team seat, scans every repo in the workspace and exports a dated Markdown migration plan per repo.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does staying on Redis OSS 5 cost compared with this check?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">In AWS's own example a cache.m5.large node on Redis OSS 5 in US East (Ohio) costs $0.156 an hour on demand, and Extended Support adds $0.1248 an hour, an 80% premium, in years one and two. Node-based ElastiCache for Valkey is priced 20% lower. The single-file check is free; the workspace plan is $29 once.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Valkey Migration Check do?", "acceptedAnswer": {"@type": "Answer", "text": "Valkey Migration Check reads Terraform, CloudFormation, compose, Kubernetes and Dockerfiles and flags each line that ties a project to Redis: ElastiCache Redis OSS 4, 5 and 6 engine versions, redis parameter group families, serverless and node caches on the redis engine, and redis:7.4 or later images. Each finding shows the Valkey replacement line and the AWS or Redis source."}}, {"@type": "Question", "name": "Who is Valkey Migration Check for?", "acceptedAnswer": {"@type": "Answer", "text": "It is for platform engineers and DevOps leads who run Redis on AWS ElastiCache through Terraform or CloudFormation. ElastiCache Redis OSS 4 and 5 caches have been billed an 80% Extended Support premium since February 1, 2026, and Redis OSS 6 caches follow on February 1, 2027. It also suits teams leaving Redis 7.4 images over the licence change."}}, {"@type": "Question", "name": "Why not ask a chatbot or read the AWS console?", "acceptedAnswer": {"@type": "Answer", "text": "The ElastiCache console lists running caches, not the Terraform line that pins each version, so the next apply can recreate a Redis OSS 5 cache. A chatbot rewrites the file you paste but does not know the Extended Support dates, and it often keeps the redis5.0 parameter group, which blocks the engine switch."}}, {"@type": "Question", "name": "What is free and what does the paid version add?", "acceptedAnswer": {"@type": "Answer", "text": "The free version runs all 8 rules on the open file in VS Code and on the web page, with the Valkey fix on every finding and no cap. The paid version, $29 once with one licence key per person or team seat, scans every repo in the workspace and exports a dated Markdown migration plan per repo."}}, {"@type": "Question", "name": "What does staying on Redis OSS 5 cost compared with this check?", "acceptedAnswer": {"@type": "Answer", "text": "In AWS's own example a cache.m5.large node on Redis OSS 5 in US East (Ohio) costs $0.156 an hour on demand, and Extended Support adds $0.1248 an hour, an 80% premium, in years one and two. Node-based ElastiCache for Valkey is priced 20% lower. The single-file check is free; the workspace plan is $29 once."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:424870,slug:"valkey-migration-check",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/aks-eks-support-cliff-lint"><span class="yj-rel-t">AKS LTS & EKS Extended Support Lint for Terraform</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/rds-extended-support-cost-lint"><span class="yj-rel-t">RDS Extended Support Cost Lint for Terraform</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cinc-migration-check"><span class="yj-rel-t">Cinc Migration Check: Chef Infra licence gate lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cloud-cost-landmine-lint"><span class="yj-rel-t">Cloud Cost Landmine Lint for Terraform, CloudFormation and Kubernetes</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/gke-extended-channel-fee-lint"><span class="yj-rel-t">GKE Extended Channel Fee Lint — Terraform</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/opentofu-migration-lint"><span class="yj-rel-t">OpenTofu Migration Lint — Terraform</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body> | |
| </html> | |