merge(codex/split-modules): split modules into alicloud/ and aws/
This commit is contained in:
commit
c890f0e83f
0
iac_modules/pulumi/modules/aws/__init__.py
Normal file
0
iac_modules/pulumi/modules/aws/__init__.py
Normal file
0
iac_modules/pulumi/modules/aws/ec2/__init__.py
Normal file
0
iac_modules/pulumi/modules/aws/ec2/__init__.py
Normal file
97
iac_modules/pulumi/modules/aws/ec2/ec2_instance.py
Normal file
97
iac_modules/pulumi/modules/aws/ec2/ec2_instance.py
Normal file
@ -0,0 +1,97 @@
|
||||
import os
|
||||
import pulumi
|
||||
import pulumi_aws as aws
|
||||
from .utils import resolve_ami
|
||||
|
||||
def create_instances(instances_config, subnets_dict, sg_map: dict, key_name, depends_on=None):
|
||||
outputs = {}
|
||||
|
||||
for instance_cfg in instances_config:
|
||||
name = instance_cfg["name"]
|
||||
subnet_name = instance_cfg["subnet"]
|
||||
subnet = subnets_dict[subnet_name]
|
||||
subnet_id = subnet.id
|
||||
|
||||
region = aws.config.region
|
||||
ami = resolve_ami(instance_cfg["ami"], region)
|
||||
instance_type = instance_cfg["type"]
|
||||
disk_size = instance_cfg["disk_size_gb"]
|
||||
|
||||
lifecycle = instance_cfg.get("lifecycle", "ondemand")
|
||||
ttl = instance_cfg.get("ttl", "none")
|
||||
env = instance_cfg.get("env", "dev")
|
||||
owner = instance_cfg.get("owner", "unknown")
|
||||
user_data_path = instance_cfg.get("user_data")
|
||||
private_ip = instance_cfg.get("private_ip", None)
|
||||
associate_public_ip = instance_cfg.get("associate_public_ip", True)
|
||||
|
||||
# ✅ User data
|
||||
user_data = None
|
||||
if user_data_path:
|
||||
expanded_path = os.path.expanduser(user_data_path)
|
||||
if os.path.exists(expanded_path):
|
||||
with open(expanded_path, "r") as f:
|
||||
user_data = f.read()
|
||||
else:
|
||||
pulumi.log.warn(f"⚠️ user_data 文件不存在: {expanded_path}")
|
||||
|
||||
tags = {
|
||||
"Name": name,
|
||||
"Lifecycle": lifecycle,
|
||||
"TTL": ttl,
|
||||
"Environment": env,
|
||||
"Owner": owner,
|
||||
}
|
||||
|
||||
# ✅ Spot 实例配置
|
||||
instance_market_options = None
|
||||
if lifecycle == "spot":
|
||||
instance_market_options = aws.ec2.InstanceInstanceMarketOptionsArgs(
|
||||
market_type="spot",
|
||||
spot_options=aws.ec2.InstanceInstanceMarketOptionsSpotOptionsArgs(
|
||||
instance_interruption_behavior="terminate",
|
||||
spot_instance_type="one-time"
|
||||
)
|
||||
)
|
||||
|
||||
# ✅ 解析 security group ids(通过名字)
|
||||
sg_names = instance_cfg.get("sg_names", [])
|
||||
security_group_ids = []
|
||||
for sg_name in sg_names:
|
||||
sg = sg_map.get(sg_name)
|
||||
if sg:
|
||||
security_group_ids.append(sg.id)
|
||||
else:
|
||||
pulumi.log.warn(f"⚠️ 实例 '{name}' 引用的 SG '{sg_name}' 未找到,已跳过")
|
||||
|
||||
# ✅ 构建依赖项
|
||||
resource_dependencies = [subnet]
|
||||
for sg in security_group_ids:
|
||||
resource_dependencies.append(sg_map.get(sg_name))
|
||||
if depends_on:
|
||||
resource_dependencies.extend(depends_on)
|
||||
|
||||
# ✅ 创建实例
|
||||
ec2 = aws.ec2.Instance(name,
|
||||
ami=ami,
|
||||
instance_type=instance_type,
|
||||
key_name=key_name,
|
||||
subnet_id=subnet_id,
|
||||
private_ip=private_ip,
|
||||
associate_public_ip_address=associate_public_ip,
|
||||
vpc_security_group_ids=security_group_ids,
|
||||
user_data=user_data,
|
||||
root_block_device={
|
||||
"volume_size": disk_size,
|
||||
"volume_type": "gp2"
|
||||
},
|
||||
instance_market_options=instance_market_options,
|
||||
tags=tags,
|
||||
opts=pulumi.ResourceOptions(depends_on=resource_dependencies)
|
||||
)
|
||||
|
||||
outputs[name + "_id"] = ec2.id
|
||||
outputs[name + "_public_ip"] = ec2.public_ip
|
||||
outputs[name + "_private_ip"] = ec2.private_ip
|
||||
|
||||
return outputs
|
||||
43
iac_modules/pulumi/modules/aws/ec2/utils.py
Normal file
43
iac_modules/pulumi/modules/aws/ec2/utils.py
Normal file
@ -0,0 +1,43 @@
|
||||
import pulumi_aws as aws
|
||||
|
||||
AMI_MAP = {
|
||||
"ubuntu-22.04": ("099720109477", "*ubuntu*22.04*"),
|
||||
"ubuntu-24.04": ("099720109477", "*ubuntu*24.04*"),
|
||||
"rocky-8.10": ("792107900819", "Rocky-8-ec2-8.10*"),
|
||||
"amazonlinux-2": ("137112412989", "amzn2-ami-hvm-*-gp2"),
|
||||
"amazonlinux-2023": ("137112412989", "al2023-ami-*-x86_64"),
|
||||
"debian-12": ("136693071363", "debian-12-*"),
|
||||
"almalinux-9": ("151447241410", "AlmaLinux-9-*"),
|
||||
}
|
||||
|
||||
def query_latest_ami(owner: str, name_filter: str, architecture: str = "x86_64") -> str:
|
||||
result = aws.ec2.get_ami(
|
||||
most_recent=True,
|
||||
owners=[owner],
|
||||
filters=[
|
||||
{"name": "name", "values": [name_filter]},
|
||||
{"name": "architecture", "values": [architecture]},
|
||||
{"name": "virtualization-type", "values": ["hvm"]},
|
||||
],
|
||||
)
|
||||
return result.id
|
||||
|
||||
def resolve_ami(ami_keyword: str, region: str, architecture: str = "x86_64") -> str:
|
||||
if not aws.config.region:
|
||||
raise ValueError("❌ AWS region is not set. Please set aws.config.region before calling resolve_ami")
|
||||
|
||||
if ami_keyword.startswith("ami-"):
|
||||
return ami_keyword
|
||||
|
||||
keyword = ami_keyword.lower()
|
||||
print(f"🔍 Resolving AMI for keyword='{keyword}' in region='{region}' with arch='{architecture}'")
|
||||
|
||||
if keyword in AMI_MAP:
|
||||
owner, name_filter = AMI_MAP[keyword]
|
||||
try:
|
||||
return query_latest_ami(owner, name_filter, architecture)
|
||||
except Exception as e:
|
||||
raise ValueError(f"❌ Failed to find AMI for '{keyword}' in region '{region}': {e}")
|
||||
|
||||
raise ValueError(f"❌ Unsupported AMI keyword: {ami_keyword}. Supported keywords: {list(AMI_MAP.keys())}")
|
||||
|
||||
66
iac_modules/pulumi/modules/aws/security_group/sg.py
Normal file
66
iac_modules/pulumi/modules/aws/security_group/sg.py
Normal file
@ -0,0 +1,66 @@
|
||||
import pulumi_aws as aws
|
||||
from pulumi_aws.ec2 import SecurityGroup, SecurityGroupIngressArgs, SecurityGroupEgressArgs
|
||||
|
||||
def create_security_group(vpc_id: str, rule_config: dict) -> SecurityGroup:
|
||||
"""
|
||||
创建 Security Group,支持 ingress/egress 配置,包括 TCP, UDP, ICMP
|
||||
:param vpc_id: 目标 VPC ID
|
||||
:param rule_config: 单个 firewall_rules 的字典配置
|
||||
:return: 创建的 SecurityGroup 资源对象
|
||||
"""
|
||||
ingress_rules = []
|
||||
|
||||
source_ranges = rule_config.get("source_ranges", ["0.0.0.0/0"])
|
||||
egress_ranges = rule_config.get("egress_ranges", ["0.0.0.0/0"])
|
||||
|
||||
for allow_rule in rule_config.get("allow", []):
|
||||
protocol = allow_rule.get("protocol", "tcp").lower()
|
||||
ports = allow_rule.get("ports", [])
|
||||
|
||||
# ICMP 无需端口处理
|
||||
if protocol == "icmp":
|
||||
ingress_rules.append(
|
||||
SecurityGroupIngressArgs(
|
||||
protocol="icmp",
|
||||
from_port=-1,
|
||||
to_port=-1,
|
||||
cidr_blocks=source_ranges
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
# 处理 TCP/UDP 等需要端口的协议
|
||||
for port in ports:
|
||||
if isinstance(port, str) and port.lower() in ["*", "any", "all"]:
|
||||
from_port, to_port = 0, 65535
|
||||
else:
|
||||
port = int(port)
|
||||
from_port = to_port = port
|
||||
|
||||
ingress_rules.append(
|
||||
SecurityGroupIngressArgs(
|
||||
protocol=protocol,
|
||||
from_port=from_port,
|
||||
to_port=to_port,
|
||||
cidr_blocks=source_ranges
|
||||
)
|
||||
)
|
||||
|
||||
# 创建 Security Group
|
||||
sg = aws.ec2.SecurityGroup(
|
||||
rule_config.get("name", "default-sg"),
|
||||
vpc_id=vpc_id,
|
||||
description=f"Security Group: {rule_config.get('name', 'N/A')}",
|
||||
ingress=ingress_rules,
|
||||
egress=[
|
||||
SecurityGroupEgressArgs(
|
||||
protocol="-1",
|
||||
from_port=0,
|
||||
to_port=0,
|
||||
cidr_blocks=egress_ranges
|
||||
)
|
||||
],
|
||||
tags={"Name": rule_config.get("name", "default-sg")}
|
||||
)
|
||||
|
||||
return sg
|
||||
0
iac_modules/pulumi/modules/aws/vpc/__init__.py
Normal file
0
iac_modules/pulumi/modules/aws/vpc/__init__.py
Normal file
76
iac_modules/pulumi/modules/aws/vpc/vpc.py
Normal file
76
iac_modules/pulumi/modules/aws/vpc/vpc.py
Normal file
@ -0,0 +1,76 @@
|
||||
import pulumi_aws as aws
|
||||
import pulumi
|
||||
|
||||
def create_vpcs(vpc_list, region):
|
||||
results = {}
|
||||
for vpc_conf in vpc_list:
|
||||
result = create_vpc(vpc_conf, region)
|
||||
results[vpc_conf["name"]] = result
|
||||
return results
|
||||
|
||||
def create_vpc(vpc_conf, region):
|
||||
vpc = aws.ec2.Vpc(vpc_conf['name'],
|
||||
cidr_block=vpc_conf['cidr_block'],
|
||||
enable_dns_support=True,
|
||||
enable_dns_hostnames=True,
|
||||
tags={"Name": vpc_conf['name']}
|
||||
)
|
||||
|
||||
# 判断是否包含公有子网
|
||||
has_public = any(subnet["type"] == "public" for subnet in vpc_conf["subnets"])
|
||||
igw = aws.ec2.InternetGateway(f"{vpc_conf['name']}-igw", vpc_id=vpc.id) if has_public else None
|
||||
|
||||
subnets = {}
|
||||
for subnet_cfg in vpc_conf["subnets"]:
|
||||
subnet = aws.ec2.Subnet(subnet_cfg["name"],
|
||||
vpc_id=vpc.id,
|
||||
cidr_block=subnet_cfg["cidr_block"],
|
||||
map_public_ip_on_launch=subnet_cfg["type"] == "public",
|
||||
availability_zone=subnet_cfg["availability_zone"],
|
||||
tags={"Name": subnet_cfg["name"]}
|
||||
)
|
||||
subnets[subnet_cfg["name"]] = subnet
|
||||
|
||||
# 路由表创建,根据 subnet_type 分组
|
||||
route_tables = {}
|
||||
|
||||
if "routes" in vpc_conf:
|
||||
for route_cfg in vpc_conf["routes"]:
|
||||
subnet_type = route_cfg["subnet_type"]
|
||||
route_table_name = f"{vpc_conf['name']}-{subnet_type}-rt"
|
||||
|
||||
# 如果还未创建该类型的路由表,则创建
|
||||
if subnet_type not in route_tables:
|
||||
route_table = aws.ec2.RouteTable(route_table_name,
|
||||
vpc_id=vpc.id,
|
||||
routes=[],
|
||||
tags={"Name": route_table_name}
|
||||
)
|
||||
route_tables[subnet_type] = route_table
|
||||
else:
|
||||
route_table = route_tables[subnet_type]
|
||||
|
||||
# 添加路由条目(追加)
|
||||
aws.ec2.Route(f"{route_table_name}-{route_cfg['destination_cidr_block'].replace('/', '-')}",
|
||||
route_table_id=route_table.id,
|
||||
destination_cidr_block=route_cfg["destination_cidr_block"],
|
||||
gateway_id=igw.id if route_cfg["gateway"] == "internet_gateway" else None
|
||||
)
|
||||
|
||||
# 路由表关联到子网
|
||||
for subnet_cfg in vpc_conf["subnets"]:
|
||||
subnet_type = subnet_cfg["type"]
|
||||
if subnet_type in route_tables:
|
||||
aws.ec2.RouteTableAssociation(f"{subnet_cfg['name']}-assoc",
|
||||
subnet_id=subnets[subnet_cfg["name"]].id,
|
||||
route_table_id=route_tables[subnet_type].id
|
||||
)
|
||||
|
||||
# TODO: Peering 支持
|
||||
|
||||
return {
|
||||
"vpc": vpc,
|
||||
"subnets": subnets,
|
||||
"igw": igw,
|
||||
"route_tables": route_tables
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user