Skip to content

Commit 1d4b349

Browse files
dsy3502zhangjing57
authored andcommitted
modify network deploy
1 parent 2e9b7f8 commit 1d4b349

File tree

9 files changed

+293
-6
lines changed

9 files changed

+293
-6
lines changed

dingo_command/__init__.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
from dingo_command.common.keystone_client import KeystoneClient
3+
from dingo_command.common.neutron import API as NeutronAPI
4+
from dingo_command.common import CONF
5+
6+
PROJECT_NAME = "dingo-command"
7+
NETWORK_NAME = "dingo-command-shared-net"
8+
NETWORK_CIDR = "172.254.0.0/16"
9+
10+
11+
12+
def init_openstack_project_and_network():
13+
# 初始化项目
14+
keystone = KeystoneClient()
15+
project = keystone.get_project_by_name(PROJECT_NAME)
16+
if not project:
17+
project = keystone.create_project(PROJECT_NAME, "default")
18+
project_id = project.id
19+
20+
# 初始化网络
21+
neutron_api = NeutronAPI()
22+
neutron = neutron_api.get_neutron_client(CONF)
23+
# 查询网络是否存在
24+
networks = neutron.list_networks(name=NETWORK_NAME).get('networks', [])
25+
if not networks:
26+
# 创建网络
27+
network = neutron.create_network({
28+
"network": {
29+
"name": NETWORK_NAME,
30+
"project_id": project_id,
31+
"shared": True
32+
}
33+
})
34+
network_id = network["network"]["id"]
35+
# 创建子网
36+
subnet = neutron.create_subnet({
37+
"subnet": {
38+
"name": f"{NETWORK_NAME}-subnet",
39+
"network_id": network_id,
40+
"ip_version": 4,
41+
"cidr": NETWORK_CIDR,
42+
"project_id": project_id
43+
}
44+
})
45+
# 初始化时自动调用
46+
init_openstack_project_and_network()

dingo_command/api/k8s/resource.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,33 @@ async def list_resources(
138138
#将resources转为json返回
139139
return resources
140140

141+
@router.get("/k8s/{resource}/list", summary="查询资源列表", description="查询资源列表")
142+
async def list_resources(
143+
cluster_id:str = Query(None, description="集群id"),
144+
resource: str = Path(..., description="Kubernetes 资源类型"),
145+
search_terms: str = Query(None, description="搜索关键词"),
146+
page: str = Query(None, description="页码"),
147+
page_size: str = Query(None, description="每页大小"),
148+
sort_by: str = Query(None, description="排序字段"),
149+
sort_order: str = Query(None, description="排序顺序"),
150+
token: str = Depends(get_token),
151+
):
152+
k8sclient = get_k8s_client_by_cluster(cluster_id)
153+
#将search_terms按照逗号分开
154+
search_terms_list = search_terms.split(",") if search_terms else []
155+
resources = k8sclient.list_resource(
156+
resource_type=resource,
157+
search_terms=search_terms_list,
158+
page=page,
159+
page_size=page_size,
160+
sort_by=sort_by,
161+
sort_order=sort_order
162+
)
163+
if resources is None:
164+
raise HTTPException(status_code=500, detail=f"查询资源 '{resource}' 失败。")
165+
#将resources转为json返回
166+
return resources
167+
141168
@router.get("/k8s/namespace/{namespace}/{resource}/{name}", summary="查询资源", description="查询资源")
142169
async def get_resources(
143170
cluster_id:str = Query(None, description="集群id"),

dingo_command/celery_api/workers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from dingo_command.services import CONF as ServiceConf
3232
from dingo_command.common.nova_client import NovaClient
3333
from dingo_command.common import neutron
34+
from dingo_command.common.network import init_cluster_network
3435
from dingo_command.common.cinder_client import CinderClient
3536
from celery.exceptions import SoftTimeLimitExceeded
3637

@@ -331,7 +332,7 @@ def create_infrastructure(cluster:ClusterTFVarsObject, task_info:Taskinfo, scale
331332
db_cluster.bus_network_cidr = bus_subnet.get("cidr")
332333
#db_cluster.status = "running"
333334
ClusterSQL.update_cluster(db_cluster)
334-
335+
init_cluster_network()
335336
# 更新任务状态为"成功"
336337
task_info.end_time = datetime.fromtimestamp(datetime.now().timestamp())
337338
task_info.state = "success"

dingo_command/common/__init__.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
CONF.register_group(cloudkitty_group)
5656
CONF.register_opts(cloudkitty_opts, cloudkitty_group)
5757

58-
# nova的配置信息
58+
# cinder的配置信息
5959
cinder_group = cfg.OptGroup(name='cinder', title='cinder conf data')
6060
cinder_opts = [
6161
cfg.StrOpt( 'auth_url', default='http://10.220.56.254:5000', help='auth url'),
@@ -71,6 +71,39 @@
7171
CONF.register_group(cinder_group)
7272
CONF.register_opts(cinder_opts, cinder_group)
7373

74+
# keystone的配置信息
75+
keystone_group = cfg.OptGroup(name='keystone', title='keystone conf data')
76+
keystone_opts = [
77+
cfg.StrOpt( 'auth_url', default='http://10.220.56.254:5000', help='auth url'),
78+
cfg.StrOpt( 'auth_type', default="password", help='auth type'),
79+
cfg.StrOpt( 'project_domain', default="default", help='project domain'),
80+
cfg.StrOpt( 'user_domain', default='default', help='user domain'),
81+
cfg.StrOpt( 'project_name', default='service', help='project name'),
82+
cfg.StrOpt( 'user_name', default='nova', help='user name'),
83+
cfg.StrOpt( 'password', default='XModTf5fcvUw7aAr3CUBBVdO38WQS15QQwNqVjGJ', help='password'),
84+
cfg.StrOpt( 'region_name', default='RegionOne', help='region name'),
85+
]
86+
# 注册nova配置
87+
CONF.register_group(keystone_group)
88+
CONF.register_opts(keystone_opts, keystone_group)
89+
90+
default_group = cfg.OptGroup(name='default', title='default conf data')
91+
92+
default_opts = [
93+
cfg.StrOpt('controller_nodes', default=None, help='the openstack controller nodes'),
94+
cfg.StrOpt('my_ip', default=None, help='the openstack host ip'),
95+
cfg.StrOpt('transport_url', default=None, help='the openstack rabbit mq url'),
96+
cfg.StrOpt('center_transport_url', default=None, help='the region one openstack rabbit mq url'),
97+
cfg.BoolOpt('center_region_flag', default=False, help='the region is center region'),
98+
cfg.StrOpt('region_name', default=None, help='the openstack region name'),
99+
cfg.StrOpt('cluster_work_dir', default='/var/lib/dingo-command', help='the openstack region name'),
100+
cfg.StrOpt('auth_url', default=None, help='the openstack region name'),
101+
cfg.StrOpt('k8s_master_image', default=None, help='the master image id'),
102+
cfg.StrOpt('k8s_master_flavor', default=None, help='the master flavor name')
103+
]
104+
CONF.register_group(default_group)
105+
CONF.register_opts(default_opts, default_group)
106+
74107
# 注册neutron配置
75108
neutron_group = cfg.OptGroup(name='neutron', title='neutron conf data')
76109
CONF.register_group(neutron_group)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from keystoneauth1 import loading, session
2+
from keystoneclient.v3 import client as keystone_client
3+
from dingo_command.common import CONF
4+
5+
class KeystoneClient:
6+
def __init__(self, conf=CONF):
7+
# 从conf中加载keystone认证信息
8+
loader = loading.get_plugin_loader('password')
9+
auth = loader.load_from_options(
10+
auth_url=conf.keystone.auth_url,
11+
username=conf.keystone.user_name,
12+
password=conf.keystone.password,
13+
project_name=conf.keystone.project_name,
14+
user_domain_name=getattr(conf.keystone, 'user_domain_name', 'Default'),
15+
project_domain_name=getattr(conf.keystone, 'project_domain_name', 'Default')
16+
)
17+
sess = session.Session(auth=auth)
18+
self.client = keystone_client.Client(session=sess)
19+
20+
def get_project_by_name(self, name):
21+
"""
22+
根据项目名称查询项目
23+
"""
24+
projects = self.client.projects.list(name=name)
25+
return projects[0] if projects else None
26+
27+
def create_project(self, name, domain=None, description=None):
28+
"""
29+
创建新项目
30+
"""
31+
domain = domain or self.client.session.get_project_domain_id()
32+
return self.client.projects.create(
33+
name=name,
34+
domain=domain,
35+
description=description
36+
)

dingo_command/common/network.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from dingo_command.common.neutron import API as NeutronAPI
2+
from dingo_command.common.nova_client import NovaClient
3+
from dingo_command.common import CONF
4+
import subprocess
5+
6+
def get_controller_nodes():
7+
#获取openstack的所有主节点
8+
control_nodes = CONF.default.controller_nodes
9+
if not control_nodes:
10+
raise Exception("No control nodes configured in the dingo-command configuration.")
11+
control_nodes = control_nodes.split(',')
12+
13+
return control_nodes
14+
15+
def get_network_ports(network_name):
16+
neutron_api = NeutronAPI()
17+
neutron = neutron_api.get_neutron_client(CONF)
18+
networks = neutron.list_networks(name=network_name).get('networks', [])
19+
if not networks:
20+
raise Exception(f"Network {network_name} not found")
21+
network_id = networks[0]['id']
22+
ports = neutron.list_ports(network_id=network_id).get('ports', [])
23+
if not ports:
24+
return None
25+
return ports[0]
26+
27+
def assign_ports_to_ovs(port):
28+
iface = port['name']
29+
mac = port['mac_address']
30+
iface_id = port['id']
31+
ip_addr = port['fixed_ips'][0]['ip_address']
32+
# 这里假设/24,实际应根据子网信息获取
33+
cmd = (
34+
f"ovs-vsctl --may-exist add-port br-int {iface} "
35+
f"-- set Interface {iface} type=internal "
36+
f"-- set Interface {iface} external-ids:iface-status=active "
37+
f"-- set Interface {iface} external-ids:attached-mac={mac} "
38+
f"-- set Interface {iface} external-ids:iface-id={iface_id} && "
39+
f"ip link set dev {iface} address {mac} && "
40+
f"ip addr add {ip_addr}/24 dev {iface} && "
41+
f"ip link set {iface} up"
42+
)
43+
subprocess.run(cmd, shell=True, check=True)
44+
45+
46+
47+
48+
def connect_network_to_vpc(project_id:str):
49+
"""
50+
将 dingo-command-shared-net 网络连接到用户 project 的路由上
51+
"""
52+
neutron_api = NeutronAPI()
53+
neutron = neutron_api.get_neutron_client(CONF)
54+
# 获取 dingo-command-shared-net 网络
55+
networks = neutron.list_networks(name="dingo-command-shared-net").get('networks', [])
56+
if not networks:
57+
raise Exception("dingo-command-shared-net 网络不存在")
58+
network_id = networks[0]['id']
59+
# 获取该网络的子网
60+
subnets = neutron.list_subnets(network_id=network_id).get('subnets', [])
61+
if not subnets:
62+
raise Exception("dingo-command-shared-net 没有子网")
63+
subnet_id = subnets[0]['id']
64+
# 获取名为cluster-router的路由器,根据project过滤
65+
port_ip = ""
66+
routers = neutron.list_routers(project_id=project_id).get('routers', [])
67+
for router in routers:
68+
if router['name'] != 'cluster-router':
69+
continue
70+
# 检查是否已连接
71+
ports = neutron.list_ports(device_id=router['id'], network_id=network_id).get('ports', [])
72+
if not ports:
73+
# 添加接口到路由器
74+
neutron.add_interface_router(router['id'], {'subnet_id': subnet_id})
75+
#获取添加到路由器上的port的ip
76+
ports = neutron.list_ports(device_id=router['id'], network_id=network_id).get('ports', [])
77+
for port in ports:
78+
print(f"路由器{router['name']} ({router['id']}) 上的端口 {port['name']} ({port['id']}) 的IP地址为 {port['fixed_ips'][0]['ip_address']}")
79+
print(f"已将子网{subnet_id}连接到路由器{router['name']} ({router['id']})")
80+
else:
81+
print(f"路由器{router['name']} ({router['id']}) 已连接该网络")
82+
port_ip = ports[0]['fixed_ips'][0]['ip_address']
83+
#返回vpc子网的cidr
84+
return subnets[0]['cidr'],port_ip
85+
86+
def init_cluster_network(project_id:str, subnet_id:str):
87+
# 初始化网络配置
88+
controller_nodes = get_controller_nodes()
89+
cidr, port_ip = connect_network_to_vpc(project_id)
90+
index = 1
91+
# 根据subnet_id获取网络的cidr
92+
subnet = neutron_api.get_subnet_by_id(subnet_id)
93+
cidr = subnet.get('cidr', cidr)
94+
print(f"VPC子网的CIDR为 {cidr}")
95+
for node in controller_nodes:
96+
print(f"正在初始化控制节点 {node['name']} 的网络配置...")
97+
#创建port
98+
port = get_network_ports("dingo-port-" + index)
99+
100+
if not port:
101+
print(f"控制节点 {node['name']} 没有找到相关网络端口,尝试创建...")
102+
# 如果没有端口,可能需要创建一个新的端口
103+
neutron_api = NeutronAPI()
104+
neutron = neutron_api.get_neutron_client(CONF)
105+
network_id = neutron.list_networks(name="dingo-command-shared-net").get('networks', [])[0]['id']
106+
port = neutron.create_port({
107+
"port": {
108+
"network_id": network_id,
109+
"name": "dingo-port-" + index,
110+
"admin_state_up": True
111+
}
112+
})
113+
114+
# 将端口分配到 OVS
115+
assign_ports_to_ovs(port)
116+
print(f"控制节点 {node['name']} 的网络端口已分配到 OVS")
117+
cmd = f"ip route add {node['name']} {cidr} via {port_ip} dev dingo-port-{node['name']}"
118+
subprocess.run(cmd, shell=True, check=True)
119+
120+
print("网络初始化完成,dingo-command-shared-net 已连接到 VPC 路由上。")
121+

dingo_command/common/neutron.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from neutronclient.v2_0 import client as neutron_client
88
from keystoneauth1 import loading
99
from keystoneauth1 import session
10-
from dingo_command.services import CONF
10+
from dingo_command.common import CONF
1111

1212
class API:
1313

@@ -17,7 +17,7 @@ def get_neutron_client(self, conf) -> neutron_client.Client:
1717
1818
参数:
1919
auth_url: Keystone认证URL
20-
username: 用户名
20+
user_name: 用户名
2121
password: 密码
2222
project_name: 项目名称
2323
project_domain_name: 项目域名称,默认为'Default'
@@ -28,8 +28,6 @@ def get_neutron_client(self, conf) -> neutron_client.Client:
2828
neutron_client.Client: Neutron客户端实例
2929
"""
3030
# 优先使用传入的参数,否则从环境变量获取
31-
sss = conf["neutron"]
32-
nb = conf["neutron"].auth_section
3331
region_name = conf.neutron.region_name
3432

3533
auth_plugin = loading.load_auth_from_conf_options(conf,

dingo_command/common/nova_client.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,16 @@ def nova_create_server(self, name, image_id, flavor_id, network_id, security_gro
184184
raise Exception(f"创建失败[HTTP {response.status_code}]: {response.text}")
185185
return response.json()['server']
186186

187+
def get_controller_nodes(self):
188+
# 获取控制节点列表
189+
nova = NovaClient()
190+
endpoint = nova.get_service_endpoint('compute')
191+
# 获取所有服务
192+
response = nova.session.get(f"{endpoint}/os-services")
193+
if response.status_code != 200:
194+
raise Exception(f"获取nova服务失败: {response.text}")
195+
services = response.json().get('services', [])
196+
# 过滤出控制节点服务
197+
controller_binaries = {"nova-scheduler", "nova-conductor", "nova-api"}
198+
controller_hosts = set(s['host'] for s in services if s['binary'] in controller_binaries)
199+
return list(controller_hosts)

dingo_command/common/test_neutron.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,22 @@
33

44
from dingo_command.utils.neutron import API as neutron
55
from dingo_command.common.cinder_client import CinderClient
6+
from dingo_command.common.network import init_cluster_network
67
from dingo_command.services import CONF
78

89

910
class TestNeutron(unittest.TestCase):
11+
def test_init_cluster_network(self):
12+
"""
13+
测试 init_cluster_network 方法
14+
"""
15+
# 假设有一个测试 project_id
16+
test_project_id = "0ad6b7751e904a35a9e99afaf1da416a"
17+
try:
18+
init_cluster_network(test_project_id, "68ebc544-0f4f-4fce-8106-7c1c31fbae4c")
19+
print("init_cluster_network 测试通过")
20+
except Exception as e:
21+
print(f"init_cluster_network 测试失败: {e}")
1022

1123
def test_list_external_networks(self):
1224
# 准备模拟数据

0 commit comments

Comments
 (0)