기능 추가
This commit is contained in:
@@ -47,6 +47,8 @@
|
||||
--ingress-class : ingressClassName 설정
|
||||
--report : report 파일 저장 경로
|
||||
--mapping : 맵핑 파일 지정 (default : mapping.yaml)
|
||||
--from-ingress-class : 기존 ingressclassname 지정 (지정된 대상만 변환)
|
||||
--namespace : 지정시 해당 namespace 내 ingress만 변환
|
||||
```
|
||||
|
||||
# 구성 (Kubernetes 실행 기준)
|
||||
|
||||
160
migrate.py
160
migrate.py
@@ -20,10 +20,17 @@ yaml.width = 4096
|
||||
# -----------------------------
|
||||
# kubectl ingress 조회
|
||||
# -----------------------------
|
||||
def kubectl_ingress():
|
||||
out = subprocess.check_output(
|
||||
["kubectl", "get", "ingress", "--all-namespaces", "-o", "yaml"]
|
||||
)
|
||||
def kubectl_ingress(namespace=None):
|
||||
cmd = ["kubectl", "get", "ingress"]
|
||||
|
||||
if namespace:
|
||||
cmd += ["-n", namespace]
|
||||
else:
|
||||
cmd.append("--all-namespaces")
|
||||
|
||||
cmd += ["-o", "yaml"]
|
||||
|
||||
out = subprocess.check_output(cmd)
|
||||
return yaml.load(out)
|
||||
|
||||
|
||||
@@ -37,7 +44,6 @@ def load_mapping(path):
|
||||
|
||||
# -----------------------------
|
||||
# annotation 렌더링
|
||||
# (모든 value를 문자열로 강제)
|
||||
# -----------------------------
|
||||
def render_annotations_block(unsupported, partial, converted):
|
||||
lines = []
|
||||
@@ -62,7 +68,7 @@ def render_annotations_block(unsupported, partial, converted):
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# 불필요한 metadata 제거
|
||||
# metadata 정리
|
||||
# -----------------------------
|
||||
def cleanup_metadata(meta):
|
||||
for k in [
|
||||
@@ -75,10 +81,46 @@ def cleanup_metadata(meta):
|
||||
meta.pop(k, None)
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# ingressClassName 기준 필터링
|
||||
# -----------------------------
|
||||
def filter_by_ingress_class(data, from_ingress_class):
|
||||
filtered = deepcopy(data)
|
||||
filtered["items"] = []
|
||||
|
||||
for item in data.get("items", []):
|
||||
spec = item.get("spec", {})
|
||||
current_class = spec.get("ingressClassName", "nginx")
|
||||
|
||||
if current_class == from_ingress_class:
|
||||
filtered["items"].append(item)
|
||||
|
||||
return filtered
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# 변환 전 원본 백업 (backup/ns/ingress.yaml)
|
||||
# -----------------------------
|
||||
def backup_original_ingress(data, backup_dir="./backup"):
|
||||
base = Path(backup_dir)
|
||||
base.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for item in data.get("items", []):
|
||||
meta = item.get("metadata", {})
|
||||
name = meta.get("name")
|
||||
namespace = meta.get("namespace", "default")
|
||||
|
||||
ns_dir = base / namespace
|
||||
ns_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with (ns_dir / f"{name}.yaml").open("w") as f:
|
||||
yaml.dump(item, f)
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# ingress 변환 로직
|
||||
# -----------------------------
|
||||
def migrate_ingress(data, mapping, ingress_class=None):
|
||||
def migrate_ingress(data, mapping, to_ingress_class=None):
|
||||
report = {
|
||||
"converted": [],
|
||||
"partial": [],
|
||||
@@ -98,8 +140,8 @@ def migrate_ingress(data, mapping, ingress_class=None):
|
||||
namespace = meta.get("namespace", "default")
|
||||
ingress_id = f"{namespace}/{name}"
|
||||
|
||||
if ingress_class:
|
||||
spec["ingressClassName"] = ingress_class
|
||||
if to_ingress_class:
|
||||
spec["ingressClassName"] = to_ingress_class
|
||||
|
||||
anns = meta.get("annotations", {}) or {}
|
||||
|
||||
@@ -123,18 +165,13 @@ def migrate_ingress(data, mapping, ingress_class=None):
|
||||
report["converted"].append(k)
|
||||
|
||||
elif support == "partial" and haproxy_key:
|
||||
partial.append(
|
||||
{"haproxy": haproxy_key, "value": v, "note": note}
|
||||
)
|
||||
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}
|
||||
)
|
||||
|
||||
else:
|
||||
unsupported.append(
|
||||
{"key": k, "value": v, "note": note}
|
||||
)
|
||||
unsupported.append({"key": k, "value": v, "note": note})
|
||||
report["unsupported"].append(k)
|
||||
report["detail"][ingress_id]["unsupported"].append(
|
||||
{"nginx": k, "value": v, "note": note}
|
||||
@@ -182,18 +219,24 @@ def write_report(report, path):
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# 파일 저장 (split)
|
||||
# 파일 저장 (yaml/ns/ingress.yaml)
|
||||
# -----------------------------
|
||||
def save_split(data, out_dir):
|
||||
Path(out_dir).mkdir(parents=True, exist_ok=True)
|
||||
def save_split(data, out_dir="./yaml"):
|
||||
base = Path(out_dir)
|
||||
base.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"
|
||||
meta = item["metadata"]
|
||||
name = meta["name"]
|
||||
namespace = meta.get("namespace", "default")
|
||||
|
||||
with open(path, "w") as f:
|
||||
ns_dir = base / namespace
|
||||
ns_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
path = ns_dir / f"{name}.yaml"
|
||||
|
||||
with path.open("w") as f:
|
||||
yaml.dump(item, f)
|
||||
|
||||
if rendered:
|
||||
@@ -206,33 +249,6 @@ def save_split(data, out_dir):
|
||||
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
|
||||
# -----------------------------
|
||||
@@ -241,37 +257,55 @@ def main():
|
||||
description="nginx ingress → HAProxy ingress migration utility"
|
||||
)
|
||||
parser.add_argument("--mapping", default="mapping.yaml")
|
||||
parser.add_argument("--single", action="store_true")
|
||||
parser.add_argument("--split", action="store_true")
|
||||
parser.add_argument("--out", default="output")
|
||||
parser.add_argument("--ingress-class")
|
||||
parser.add_argument("--out", default="./yaml")
|
||||
parser.add_argument("--ingress-class", help="target ingressClassName")
|
||||
parser.add_argument(
|
||||
"--from-ingress-class",
|
||||
default="nginx",
|
||||
help="source ingressClassName (default: nginx)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--namespace",
|
||||
help="target namespace (default: all namespaces)",
|
||||
)
|
||||
parser.add_argument("--report", default="migration-report.md")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.single and not args.split:
|
||||
parser.error("one of --single or --split must be specified")
|
||||
if not args.split:
|
||||
parser.error("--split must be specified")
|
||||
|
||||
# 🔹 기본 디렉토리 보장
|
||||
Path("./backup").mkdir(parents=True, exist_ok=True)
|
||||
Path(args.out).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
ingress = kubectl_ingress(args.namespace)
|
||||
|
||||
ingress = filter_by_ingress_class(
|
||||
ingress,
|
||||
args.from_ingress_class,
|
||||
)
|
||||
|
||||
backup_original_ingress(ingress)
|
||||
|
||||
ingress = kubectl_ingress()
|
||||
mapping = load_mapping(args.mapping)
|
||||
|
||||
converted, report = migrate_ingress(
|
||||
ingress, mapping, ingress_class=args.ingress_class
|
||||
ingress,
|
||||
mapping,
|
||||
to_ingress_class=args.ingress_class,
|
||||
)
|
||||
|
||||
if args.single:
|
||||
out_file = args.out if args.out.endswith(".yaml") else f"{args.out}.yaml"
|
||||
save_single(converted, out_file)
|
||||
|
||||
if args.split:
|
||||
save_split(converted, args.out)
|
||||
|
||||
write_report(report, args.report)
|
||||
|
||||
print("\n=== Migration Summary ===")
|
||||
print(f"Converted : {len(report['converted'])}")
|
||||
print(f"Partial : {len(report['partial'])}")
|
||||
print(f"Unsupported: {len(report['unsupported'])}")
|
||||
print(f"Backup : ./backup/<namespace>/<ingress>.yaml")
|
||||
print(f"Output : {args.out}/<namespace>/<ingress>.yaml")
|
||||
print(f"Report : {args.report}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user