- 积分
- 16841
在线时间 小时
最后登录1970-1-1
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?开始注册
x
/ l7 s0 e3 D2 n! h非常好 这一步就是把你的 openstack Neutron 网络管理模块从「仅网络层」扩展到完整的 网络 + 子网 + 端口管理功能。# ?% F' ?8 f! I
下面我给你完整规划 + 代码框架(基于你现有的 network_list_view 和 edit_network_view 结构,可直接嵌入项目)。; Y5 _7 \: j% F/ ^1 k1 \
3 m5 c+ N) A2 K' h1 D6 n$ v
( |7 S" I G8 s
一、总体架构设计" [' v; B9 w1 Y4 s' b
, _8 U4 B* C7 }. E H9 r( T我们按功能模块划分成三个部分:
& @4 K0 i. b8 D- _" W; ?9 K B( R( e* s! F( f U
networks/
5 @, l6 M% w! N0 S, c- G) a5 ]├── views/
0 R/ E7 V5 V6 ?7 l3 K! m& w, w" a│ ├── networks.py # 网络的增删改查
( W. C! `; R7 u& k8 V1 r$ `8 j5 c. l3 U│ ├── subnets.py # 子网管理(新增/编辑/删除)) O. {( Z; Z- n) a
│ ├── ports.py # 端口管理(创建/删除/绑定安全组/绑定虚机)
* [, r! {$ i! d' `6 ?│9 X8 W4 d# J5 C4 x9 W' u8 t
├── templates/
4 w d, n! d9 ]" A$ t│ ├── networks.html- @4 g' B# l2 u: Z3 ~
│ ├── network_edit.html
3 G; g+ b2 Q. `3 u│ ├── subnets.html" T' f! @9 U h; i
│ ├── subnet_edit.html
: h m# G; _9 y/ w( |│ ├── ports.html
4 p6 Z Z* l0 e+ ?( ^│ ├── port_edit.html
" w# k. T1 M" }) A│( p$ b+ [# e" D8 e! s) ?& e
└── urls.py # 统一注册URL
L( C5 G5 P! L, E
$ G( x& r: K9 p! l9 E/ K4 v 二、子网管理 Subnets 功能2 ^" N J4 m% N/ B
子网列表8 q K7 Y4 f3 K9 I
# views/subnets.py
) R: v2 b+ n) {" Vimport requests
: S- d: a; } A' @9 Q: j7 ]from django.shortcuts import render, redirect
4 r- b5 V, E3 b' A: ifrom django.contrib import messages4 g( H' ` j' ^: j: A6 g& X
from django.views.decorators.csrf import csrf_exempt
- I* Z- J, @( {0 D# W% [
! T( ^0 I. \) E@csrf_exempt
' x9 W3 v$ ~0 d- m3 R2 h3 C& u# m tdef subnet_list_view(request, network_id):5 P# m# t6 c1 a: o# f% ?" J* w" [
"""查看指定网络的所有子网"""
4 Q7 z8 p! L' l# {/ R8 N F6 p token = request.session.get("token")+ M8 U; P/ o- Q) U
headers = {"X-Auth-Token": token} F9 P0 C* F. R. G+ ?
resp = requests.get(f"{Neutron_Base}/subnets", headers=headers, timeout=10)
% o' B2 w8 }2 a/ H" ~7 B+ w
; v! z; A" V, ^" G0 @1 S2 n. P if resp.status_code == 200:
. _$ l! }$ t: h* p: B all_subnets = resp.json().get("subnets", [])2 y0 x- f$ v; Y }; M
subnets = [s for s in all_subnets if s["network_id"] == network_id]
; Z/ q0 v, w1 `8 c1 v* ] else:
X, l. Q$ Q5 z, a messages.error(request, f"无法获取子网列表: {resp.text}")
) Z k0 L( Q# b. D subnets = []
4 U6 [) Q' a" R: z
0 T# x5 F$ V. I7 @; M1 X return render(request, "subnets.html", {"subnets": subnets, "network_id": network_id})
* F( H) _) R6 B# L! V+ G/ c M; W; f# ~9 }( E; l
新建子网
! d% b! b( w6 c* o@csrf_exempt, X( I- l6 S1 M5 T/ ^3 `6 c$ T$ o8 K7 H
def subnet_create_view(request, network_id):
' g, v& g) {0 { if request.method == "POST":1 P ^1 N" g8 o) w2 |( c6 A6 W
token = request.session.get("token")
, C; H% j/ M4 B U) M headers = {"X-Auth-Token": token, "Content-Type": "application/json"}1 m; |. Y6 E: l4 O% t7 O
" [. { ]5 l" b( _# ? name = request.POST.get("name")( |0 x( k4 a& e
cidr = request.POST.get("cidr")+ Q' v( b1 m5 _3 m' M1 \2 _
gateway_ip = request.POST.get("gateway_ip")
+ s6 ~2 o& j& D& w enable_dhcp = request.POST.get("enable_dhcp") == "on"6 p! l3 a- m# @
4 M* y4 X7 \$ X4 y* l* n data = {
1 X! O8 b5 b* y8 @* L* f; R "subnet": {) y7 |8 S4 E8 A' m6 G2 V' ^
"network_id": network_id,
- f5 d5 Y- n; z/ f4 P. C/ z! \- n1 S "ip_version": 4,0 \4 X, q7 J! v5 c y& x
"cidr": cidr,
* O5 x2 Q# A$ m' R1 y* o "gateway_ip": gateway_ip,% y; Y7 Q" F% N; [
"enable_dhcp": enable_dhcp,2 l% ^: h5 F6 P* n
"name": name,5 {. g9 j7 K. Z B
}
4 l4 T- h$ [7 m( _ }7 f2 q9 i! q5 T( G1 g9 t
$ t9 }5 f' r) U6 D5 l4 c
resp = requests.post(f"{Neutron_Base}/subnets", headers=headers, json=data, timeout=15)
- \9 N# O: ?& r if resp.status_code in [200, 201]:
/ r0 F! V. t7 g messages.success(request, "子网创建成功")
1 L) q% C; S+ _- z2 T else:
) P7 y v; Q$ A# a2 G: i messages.error(request, f"子网创建失败: {resp.text}")
0 i0 z) f: I* @% v3 X return redirect("subnet_list", network_id=network_id)
7 v8 L7 s2 C+ D: H, X" \
# M% o2 y2 c/ {1 s/ j2 e* G return render(request, "subnet_edit.html", {"network_id": network_id})& ^% K" t7 ^3 Q, v! U
8 x3 ~2 `# ]9 t6 o删除子网6 t2 W l% i' C3 r% B, O$ q+ o
def subnet_delete_view(request, subnet_id, network_id):
E4 t" h6 W, c8 B5 f; n token = request.session.get("token")! L3 H! F$ I+ u% V! j( D
headers = {"X-Auth-Token": token}
( [% Q6 h7 H& G$ ? resp = requests.delete(f"{Neutron_Base}/subnets/{subnet_id}", headers=headers, timeout=10)
* L% w) \7 C5 H. A
+ ^& m& x# {% Y \: _2 S! Z `. F if resp.status_code == 204:& L2 J9 ~0 A- q/ M! t
messages.success(request, "子网已删除")
& d3 d- X- x0 ^ j1 R6 y else:( c( l* w3 [" Q+ G8 [& d5 ~
messages.error(request, f"删除失败: {resp.text}")
- H3 y" g) @& ~: {4 q* ^+ y4 Q return redirect("subnet_list", network_id=network_id)
b" S9 G/ M9 U6 Z
9 Z) s6 s+ g5 \ 三、端口 Ports 管理1 Y5 i! q5 ~7 [" P
端口列表
2 c# P; `" M1 Bdef port_list_view(request, network_id):1 G1 `( i$ y7 X) x' q0 g# D
token = request.session.get("token")
8 G4 f( H( t# O1 ^% i* D; Z headers = {"X-Auth-Token": token}
- B8 Y& @/ h% U! f! o/ A resp = requests.get(f"{Neutron_Base}/ports", headers=headers, timeout=10)
% K! b |. s( Y& ?: }) \3 s
& J* V) G, d+ s; h0 M if resp.status_code == 200:
# Z' h- B" [/ R6 A; c ports = [p for p in resp.json().get("ports", []) if p["network_id"] == network_id]+ C3 U8 S0 P- p4 g9 z
else:1 J, u; x5 N& Q5 l( J
ports = []
1 ]6 T1 V: G8 ]& M" A/ M4 v b messages.error(request, f"无法获取端口: {resp.text}")6 _) x' w( {; W# z- t- K
, W- Q8 i( X9 L/ | J return render(request, "ports.html", {"ports": ports, "network_id": network_id})$ A" d' O3 E+ R8 A8 l |
* w* u; H) }, h- R; F
新建端口& ~3 c X, [3 W% }; [+ A
@csrf_exempt
] \/ g6 F4 n! }% f! k: u, B+ |def port_create_view(request, network_id):
$ g) |; w8 N7 E2 N if request.method == "POST":
. D; B+ `, u9 {8 Z4 j: H) P+ v5 ~* d token = request.session.get("token")
R: s* Z4 t; g( }3 d$ F headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
& r8 o$ h: y" a" J" p3 t6 H- E- h9 L3 I/ W' o! ~
name = request.POST.get("name")! n( _+ u6 U( A9 D
data = {
. H3 Y* \0 b' s. n7 `. `) _ "port": {! v0 L" ~* \ U4 ~
"network_id": network_id,. w* ~, e) m% R' g ~
"name": name,
2 x# M! T* ^; a* e& V4 q "admin_state_up": True& ?* O# ]6 [2 ?" ~3 j9 X
}& \' q! s1 G! C8 e$ E# a$ u0 O
}
' P6 V% F' \+ A6 L" C3 ^. h) @ resp = requests.post(f"{Neutron_Base}/ports", headers=headers, json=data, timeout=10)3 I, V! ~: Z, P+ X& o; C
if resp.status_code in [200, 201]:. H( \! F X5 L8 l
messages.success(request, "端口创建成功")9 k5 n2 ]$ c) e2 c6 T
else:, F/ y3 n; |2 [% C {7 D
messages.error(request, f"创建失败: {resp.text}")
" k( G! u! u, x+ B% n; R return redirect("port_list", network_id=network_id)
9 F* R \5 e0 S! v2 z/ P
+ O, E0 s( @( v) ` return render(request, "port_edit.html", {"network_id": network_id})
w) R6 y% v' X$ |, Z; z4 ~$ a3 R: B- A% E6 Y) v3 h! a' E
删除端口7 D: H8 {: ~' p Q/ N1 ?% F
def port_delete_view(request, port_id, network_id):
0 r9 H& g( T# f. p; x% `' z4 Z token = request.session.get("token")
* ?2 F7 j' K0 s% u) x- \% H headers = {"X-Auth-Token": token}
: E- L5 o2 r o! X2 V) X* [. J resp = requests.delete(f"{Neutron_Base}/ports/{port_id}", headers=headers, timeout=10)
5 i2 N) R8 j- i3 G0 @+ b/ n" f3 \
: f# x: e3 s- y0 k1 o5 V if resp.status_code == 204:- q* L# D( I- a( H
messages.success(request, "端口已删除")
- g% x% F5 J6 Z' |8 ^+ l else:
( } g3 {! ?; Q2 S messages.error(request, f"删除失败: {resp.text}")
U8 F# u7 x5 F& K
! B7 j( J" h6 z. o- i8 n8 i( o return redirect("port_list", network_id=network_id)
+ U) x9 t, Q4 g, F4 \
% U: w, a) s8 j/ t4️⃣ 更新安全组绑定
5 j$ W1 R' y2 D& a7 v@csrf_exempt
* v' _: ^# f) I x3 Adef port_update_sg_view(request, port_id, network_id):
" M# I, v& q& M7 w* E if request.method == "POST":
! ], T0 u" Q6 W3 S( _. p2 s token = request.session.get("token")
. [$ S8 Y3 ^( z/ m2 X+ G headers = {"X-Auth-Token": token, "Content-Type": "application/json"}- N* g/ C: Q- n6 d
sg_id = request.POST.get("security_group_id")& W2 `7 W3 s2 J8 _
! r( R3 M) u& `9 O" O* Q( \/ p; X data = {"port": {"security_groups": [sg_id]}}
: G* X0 N/ Z; t0 g6 w resp = requests.put(f"{Neutron_Base}/ports/{port_id}", headers=headers, json=data, timeout=10)
( D$ Z. I/ o: B! J# K' j5 I! y( \6 ~9 @. a# [
if resp.status_code in [200, 202]:
& T5 k" }. Q7 P' f5 w4 J; u messages.success(request, "安全组更新成功")* N$ O8 t3 y9 m- Q
else:: M) ~ y( M3 k
messages.error(request, f"安全组更新失败: {resp.text}")
* a6 {5 \! l( ?* c1 o! }( H, l5 ]' G! s- H' V5 p! y( ]
return redirect("port_list", network_id=network_id)
3 c8 |3 o: @1 L, ]6 |. c. u! r- P$ M9 v
绑定虚机(实例)接口( w; T& p7 C+ N) ?- B
@csrf_exempt
& w6 J( V, x. Y4 `0 \def port_bind_instance_view(request, port_id, server_id, network_id):3 Q7 k1 k8 z' |5 P: r: m# H, V
token = request.session.get("token")
N# j; ]$ ~* v headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
) N2 O# `* l, v9 \" f1 [% u* s# _7 c7 Q4 ]/ @% M
data = {' V* E; ]* [* T8 o
"port": {
, M2 ]' \$ X; t5 m0 `3 s) T "device_id": server_id,
, a8 z5 e: l: u. G4 F& e "device_owner": "compute:nova"* A" {! m; |- c& P: ?
}) g! O! ~! i3 ]3 v2 B K( |; Z$ f
}
' h) E0 v& I4 U8 H. r" F
8 |7 {% d2 E [9 I/ v( X2 Q$ i1 S4 C* N resp = requests.put(f"{Neutron_Base}/ports/{port_id}", headers=headers, json=data, timeout=10)
7 W9 v+ C, T0 i6 `. G5 Y if resp.status_code in [200, 202]:
8 O: l) k; h" n* J- r0 s" k) Q messages.success(request, "端口成功绑定到虚机")
1 p4 q+ D+ m) R0 b1 S4 Q; s+ K else:
0 E" W' n; ~: D9 I9 w- k messages.error(request, f"绑定失败: {resp.text}")% n" O: l/ H7 D* P, M2 M0 }3 Z
return redirect("port_list", network_id=network_id)3 x" ~, R! t r4 }
$ x3 o0 p+ \( O5 n* H7 U5 R4 s
四、URL 路由示例
6 `8 D7 i5 C4 V4 T$ y' X' a, F- G# urls.py4 Q0 }$ p9 M; C
from django.urls import path
6 r& o/ o# x+ hfrom .views import networks, subnets, ports% E8 c/ j; Y4 X6 \( a \ w/ z
6 s. M/ f9 l, H% K
urlpatterns = [
- d! p* C( ^$ q' I path("networks/", networks.network_list_view, name="networks"),7 L' e* i1 V2 N* t
path("networks/edit/<str:network_id>/", networks.edit_network_view, name="edit_network"),
6 a `- u _4 P" N9 [- j- H% D, j+ W/ R1 H; h1 w& {
path("networks/<str:network_id>/subnets/", subnets.subnet_list_view, name="subnet_list"),
7 _- h# S) l) \" ~) X% K path("networks/<str:network_id>/subnets/create/", subnets.subnet_create_view, name="subnet_create"),
* N) q/ o" Y5 C: K path("networks/<str:network_id>/subnets/delete/<str:subnet_id>/", subnets.subnet_delete_view, name="subnet_delete"), D3 _4 I$ K# x$ m9 ~, k7 f& d# r
& N' p5 b, C& n; ~+ ] path("networks/<str:network_id>/ports/", ports.port_list_view, name="port_list"),/ E1 ~8 T1 L2 @. N& ? a9 B
path("networks/<str:network_id>/ports/create/", ports.port_create_view, name="port_create"),
) ^! P" F+ J2 X! t: s( E- l path("networks/<str:network_id>/ports/delete/<str:port_id>/", ports.port_delete_view, name="port_delete"),: F4 K) X4 X( W4 C M5 T
path("networks/<str:network_id>/ports/update_sg/<str:port_id>/", ports.port_update_sg_view, name="port_update_sg"),
- |. ^; u, H7 g5 l path("networks/<str:network_id>/ports/bind/<str:port_id>/<str:server_id>/", ports.port_bind_instance_view, name="port_bind_instance"),0 l$ A1 d8 |" A. K5 ?; n S$ u. B
]
$ W/ @5 ^% o Q6 l2 R' Q& o8 K) T0 t+ h( U
|
|