| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- #!/usr/bin/env python3
- import argparse
- from pathlib import Path
- def normalize_product_version(raw: str) -> str:
- if raw is None:
- return "Edge"
- s = str(raw).strip()
- if not s:
- return "Edge"
- sl = s.lower()
- if sl == "ai":
- return "AI"
- if sl == "cmp":
- return "CMP"
- if sl == "edge":
- return "Edge"
- if sl == "lightedge":
- return "LightEdge"
- if sl == "fullstack":
- return "FullStack"
- # Keep behavior predictable; original sh supported only these values.
- return s
- def build_yaml(product_version: str, cfg: dict) -> str:
- # Keep values consistent with the original generate-ha-config.sh template,
- # but all variables must come from CLI args (no hard-coded environment).
- DB_IP = cfg["db_ip"]
- DB_PORT = cfg["db_port"]
- DB_PSWD = cfg["db_password"]
- DB_USER = cfg["db_user"]
- K8S_VIP = cfg["k8s_vip"]
- PRIMARY_INTERFACE = cfg["primary_interface"]
- PRIMARY_IP = cfg["primary_ip"]
- MASTER_1_INTERFACE = cfg["master_1_interface"]
- MASTER_1_IP = cfg["master_1_ip"]
- MASTER_2_INTERFACE = cfg["master_2_interface"]
- MASTER_2_IP = cfg["master_2_ip"]
- REGION = cfg["region"]
- ZONE = cfg["zone"]
- version = (Path(__file__).resolve().parent / "VERSION").read_text(encoding="utf-8").strip()
- ai_extra_primary = ""
- ai_extra_master = ""
- if product_version == "AI":
- ai_extra_primary = " enable_containerd: true"
- ai_extra_master = " enable_containerd: true"
- # Note: no YAML library is used; we rely on deterministic text templates.
- return f"""# primary_master_node 表示运行 k8s 和 Cloudpods 服务的节点
- primary_master_node:
- # ssh login IP
- hostname: {PRIMARY_IP}
- # 不使用本地登录方式
- use_local: false
- # ssh login user
- user: root
- # cloudpods version
- onecloud_version: {version}
- # mariadb connection address
- db_host: "{DB_IP}"
- # mariadb user
- db_user: "{DB_USER}"
- # mariadb password
- db_password: "{DB_PSWD}"
- # mariadb port
- db_port: "{DB_PORT}"
- # 节点服务监听的地址,多网卡时可以指定对应网卡的地址
- node_ip: "{PRIMARY_IP}"
- # 对应 Kubernetes calico 插件默认网卡选择规则
- ip_autodetection_method: "can-reach={PRIMARY_IP}"
- # K8s 控制节点的 IP,对应keepalived 监听的 VIP
- controlplane_host: {K8S_VIP}
- # K8s 控制节点 apiserver 监听的端口
- controlplane_port: "6443"
- # 该节点作为 Cloudpods 私有云计算节点,如果不想让控制节点作为计算节点,可以设置为 false
- as_host: true
- # 虚拟机可作为 Cloudpods 内置私有云计算节点(默认为 false)。开启此项时,请确保 as_host: true
- as_host_on_vm: true
- # 产品版本,从 [Edge, CMP, FullStack] 选择一个,FullStack 会安装融合云,CMP 安装多云管理版本,Edge 安装私有云
- product_version: '{product_version}'
- {ai_extra_primary}
- # 服务对应的镜像仓库,如果待部署的机器不在中国大陆,可以用 dockerhub 的镜像仓库:docker.io/yunion
- image_repository: registry.cn-beijing.aliyuncs.com/yunion
- # 启用高可用模式
- high_availability: true
- # 使用 minio 作为后端虚拟机镜像存储
- enable_minio: true
- ha_using_local_registry: false
- # 计算节点默认网桥 br0 对应的网卡
- host_networks: "{PRIMARY_INTERFACE}/br0/{PRIMARY_IP}"
- # region 设置
- region: {REGION}
- # zone 设置
- zone: {ZONE}
- master_nodes:
- # 加入控制节点的 k8s vip
- controlplane_host: {K8S_VIP}
- # 加入控制节点的 K8s apiserver 端口
- controlplane_port: "6443"
- # 作为 K8s 和 Cloudpods 控制节点
- as_controller: true
- # 该节点作为 Cloudpods 私有云计算节点,如果不想让控制节点作为计算节点,可以设置为 false
- as_host: true
- # 虚拟机可作为 Cloudpods 内置私有云计算节点(默认为 false)。开启此项时,请确保 as_host: true
- as_host_on_vm: true
- {ai_extra_master}
- # 从 primary 节点同步 ntp 时间
- ntpd_server: "{PRIMARY_IP}"
- # 启用高可用模式
- high_availability: true
- hosts:
- - user: root
- hostname: "{MASTER_1_IP}"
- # 计算节点默认网桥 br0 对应的网卡
- host_networks: "{MASTER_1_INTERFACE}/br0/{MASTER_1_IP}"
- - user: root
- hostname: "{MASTER_2_IP}"
- # 计算节点默认网桥 br0 对应的网卡
- host_networks: "{MASTER_2_INTERFACE}/br0/{MASTER_2_IP}"
- """
- def main() -> int:
- parser = argparse.ArgumentParser(description="Generate config-ha.yml for HA deployment")
- parser.add_argument(
- "--product-version",
- dest="product_version",
- required=True,
- help="Product version: Edge/CMP/FullStack/LightEdge/AI",
- )
- # All deployment parameters are required so users can fully control the generated YAML.
- parser.add_argument("--db-ip", dest="db_ip", required=True, help="MARIADB db_host")
- parser.add_argument("--db-port", dest="db_port", required=True, type=int, help="MARIADB db_port")
- parser.add_argument("--db-user", dest="db_user", required=True, help="MARIADB db_user")
- parser.add_argument("--db-password", dest="db_password", required=True, help="MARIADB db_password")
- parser.add_argument("--k8s-vip", dest="k8s_vip", required=True, help="keepalived/controlplane VIP")
- parser.add_argument("--primary-interface", dest="primary_interface", required=True, help="primary host NIC for br0")
- parser.add_argument("--primary-ip", dest="primary_ip", required=True, help="primary host ssh/cluster IP")
- parser.add_argument("--master-1-interface", dest="master_1_interface", required=True, help="master-1 NIC for br0")
- parser.add_argument("--master-1-ip", dest="master_1_ip", required=True, help="master-1 hostname IP")
- parser.add_argument("--master-2-interface", dest="master_2_interface", required=True, help="master-2 NIC for br0")
- parser.add_argument("--master-2-ip", dest="master_2_ip", required=True, help="master-2 hostname IP")
- parser.add_argument("--region", dest="region", required=True, help="product region")
- parser.add_argument("--zone", dest="zone", required=True, help="product zone")
- args = parser.parse_args()
- product_version = normalize_product_version(args.product_version)
- print(f"Normalized PRODUCT_VERSION: {product_version}")
- cfg_path = Path(__file__).resolve().parent / "config-ha.yml"
- cfg = {
- "db_ip": args.db_ip,
- "db_port": args.db_port,
- "db_password": args.db_password,
- "db_user": args.db_user,
- "k8s_vip": args.k8s_vip,
- "primary_interface": args.primary_interface,
- "primary_ip": args.primary_ip,
- "master_1_interface": args.master_1_interface,
- "master_1_ip": args.master_1_ip,
- "master_2_interface": args.master_2_interface,
- "master_2_ip": args.master_2_ip,
- "region": args.region,
- "zone": args.zone,
- }
- cfg_path.write_text(build_yaml(product_version, cfg), encoding="utf-8")
- print(f"Write configuration: {cfg_path.name}")
- return 0
- if __name__ == "__main__":
- raise SystemExit(main())
|