From 530d7dd5f97a55ce190c96e484e83e0f9f7e5bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B3=80=EC=A0=95=ED=9B=88?= Date: Tue, 30 Dec 2025 19:58:26 +0900 Subject: [PATCH] =?UTF-8?q?unsupported=20=EB=B6=80=EB=B6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mapping.yaml | 15 ++++ migrate.py | 198 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 139 insertions(+), 74 deletions(-) diff --git a/mapping.yaml b/mapping.yaml index 6ece837..a09b9b8 100644 --- a/mapping.yaml +++ b/mapping.yaml @@ -71,7 +71,22 @@ nginx.ingress.kubernetes.io/enable-cors: haproxy: haproxy.org/enable-cors support: full +nginx.ingress.kubernetes.io/app-root: + haproxy: haproxy.org/path-rewrite + support: partial + note: "Chage Value" + nginx.ingress.kubernetes.io/configuration-snippet: haproxy: null support: unsupported note: "HAProxy does not support arbitrary NGINX snippets" + +proxy-buffering: + haproxy: null + support: unsupported + note: "HAProxy does not support arbitrary NGINX snippets" + +gzip-level: + haproxy: null + support: unspported + note: "HAProxy does not support arbitrary NGINX snippets" diff --git a/migrate.py b/migrate.py index 18d17cd..c7ef9ce 100644 --- a/migrate.py +++ b/migrate.py @@ -15,6 +15,7 @@ from ruamel.yaml.comments import CommentedMap yaml = YAML() yaml.preserve_quotes = True yaml.indent(mapping=2, sequence=4, offset=2) +yaml.width = 4096 # ----------------------------- @@ -35,6 +36,34 @@ def load_mapping(path): return yaml.load(f) +# ----------------------------- +# annotation 렌더링 +# ----------------------------- +def render_annotations_block(unsupported, partial, converted): + """ + annotations 하위에 그대로 삽입될 문자열을 생성 + """ + lines = [] + + if unsupported: + note = unsupported[0]["note"] + lines.append(f" # {note}") + for u in unsupported: + lines.append(f" #{u['key']}: {u['value']}") + lines.append("") + + if partial: + for p in partial: + lines.append(f" # PARTIAL SUPPORT: {p['note']}") + lines.append(f" {p['haproxy']}: {p['value']}") + lines.append("") + + for c in converted: + lines.append(f" {c['haproxy']}: {c['value']}") + + return "\n".join(lines) + + # ----------------------------- # ingress 변환 로직 # ----------------------------- @@ -60,51 +89,48 @@ def migrate_ingress(data, mapping, ingress_class=None): spec["ingressClassName"] = ingress_class anns = meta.get("annotations", {}) or {} - new_anns = CommentedMap() + + unsupported = [] + partial = [] + converted = [] for k, v in anns.items(): - if k in mapping: - rule = mapping[k] - support = rule.get("support", "unsupported") - haproxy_key = rule.get("haproxy") + rule = mapping.get(k) - if support == "full": - new_anns[haproxy_key] = v - report["converted"].append(k) + if not rule: + converted.append({"haproxy": k, "value": v}) + continue - elif support == "partial": - new_anns[haproxy_key] = v - note = rule.get("note", "") - new_anns.yaml_set_comment_before_after_key( - haproxy_key, - before=f"PARTIAL SUPPORT: {note}", - ) - report["partial"].append(k) - report["detail"][ingress_id]["partial"].append( - { - "nginx": k, - "haproxy": haproxy_key, - "note": note, - } - ) + support = rule.get("support", "unsupported") + haproxy_key = rule.get("haproxy") + note = rule.get("note", "no HAProxy equivalent") - else: - lines = [f"UNSUPPORTED {k}:"] - for line in str(v).splitlines(): - lines.append(f" {line}") - new_anns.yaml_set_end_comment("\n".join(lines)) + if support == "full" and haproxy_key: + converted.append({"haproxy": haproxy_key, "value": v}) + report["converted"].append(k) + + elif support == "partial" and haproxy_key: + partial.append( + {"haproxy": haproxy_key, "value": v, "note": note} + ) + report["partial"].append(k) + report["detail"][ingress_id]["partial"].append( + {"nginx": k, "haproxy": haproxy_key, "note": note} + ) - report["unsupported"].append(k) - report["detail"][ingress_id]["unsupported"].append( - { - "nginx": k, - "value": v, - } - ) else: - new_anns[k] = v + unsupported.append( + {"key": k, "value": v, "note": note} + ) + report["unsupported"].append(k) + report["detail"][ingress_id]["unsupported"].append( + {"nginx": k, "value": v, "note": note} + ) - meta["annotations"] = new_anns + meta["annotations"] = CommentedMap() + item["_rendered_annotations"] = render_annotations_block( + unsupported, partial, converted + ) return new, report @@ -121,51 +147,78 @@ def write_report(report, path): f.write(f"- Unsupported: {len(report['unsupported'])}\n\n") f.write("---\n\n") - if any(v["partial"] for v in report["detail"].values()): - f.write("## ⚠️ Partial Support\n\n") - for ingress, items in report["detail"].items(): - if not items["partial"]: - continue - f.write(f"### {ingress}\n") - for p in items["partial"]: - f.write( - f"- {p['nginx']}\n" - f" - mapped to: {p['haproxy']}\n" - f" - note: {p['note']}\n" - ) - f.write("\n") + for ingress, detail in report["detail"].items(): + if not detail["partial"] and not detail["unsupported"]: + continue - if any(v["unsupported"] for v in report["detail"].values()): - f.write("## ❌ Unsupported\n\n") - for ingress, items in report["detail"].items(): - if not items["unsupported"]: - continue - f.write(f"### {ingress}\n") - for u in items["unsupported"]: - f.write(f"- {u['nginx']}\n") - f.write(" ```nginx\n") - f.write(f"{u['value']}\n") - f.write(" ```\n") - f.write("\n") + f.write(f"## {ingress}\n\n") + + for p in detail["partial"]: + f.write( + f"- PARTIAL {p['nginx']} → {p['haproxy']}\n" + f" - note: {p['note']}\n" + ) + + for u in detail["unsupported"]: + f.write( + f"- UNSUPPORTED {u['nginx']}\n" + f" - note: {u['note']}\n" + ) + + f.write("\n") # ----------------------------- -# 파일 저장 +# 파일 저장 (split) # ----------------------------- -def save_single(data, out_path): - with open(out_path, "w") as f: - yaml.dump(data, f) - - def save_split(data, out_dir): Path(out_dir).mkdir(parents=True, exist_ok=True) + for item in data.get("items", []): + rendered = item.pop("_rendered_annotations", "") name = item["metadata"]["name"] namespace = item["metadata"].get("namespace", "default") path = Path(out_dir) / f"{namespace}__{name}.yaml" + with open(path, "w") as f: yaml.dump(item, f) + if rendered: + content = path.read_text() + content = content.replace( + "metadata:\n", + "metadata:\n annotations:\n" + rendered + "\n", + 1, + ) + path.write_text(content) + + +# ----------------------------- +# 파일 저장 (single) +# ----------------------------- +def save_single(data, out_path): + rendered_map = {} + + for item in data.get("items", []): + rendered_map[id(item)] = item.pop("_rendered_annotations", "") + + path = Path(out_path) + with path.open("w") as f: + yaml.dump(data, f) + + content = path.read_text() + + for item in data.get("items", []): + rendered = rendered_map.get(id(item)) + if rendered: + content = content.replace( + "metadata:\n", + "metadata:\n annotations:\n" + rendered + "\n", + 1, + ) + + path.write_text(content) + # ----------------------------- # main @@ -180,9 +233,7 @@ def main(): parser.add_argument("--out", default="output") parser.add_argument("--ingress-class") parser.add_argument( - "--report", - default="migration-report.md", - help="migration summary report file", + "--report", default="migration-report.md" ) args = parser.parse_args() @@ -194,9 +245,7 @@ def main(): mapping = load_mapping(args.mapping) converted, report = migrate_ingress( - ingress, - mapping, - ingress_class=args.ingress_class, + ingress, mapping, ingress_class=args.ingress_class ) if args.single: @@ -217,3 +266,4 @@ def main(): if __name__ == "__main__": main() +