找回密码
 注册
查看: 55|回复: 0

新增neutron中subnet的删除,修改以及端口的操作

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2025-11-12 10:33:40 | 显示全部楼层 |阅读模式
' L( m( e6 g6 Z6 l, X
非常好 这一步就是把你的 OpenStack Neutron 网络管理模块从「仅网络层」扩展到完整的 网络 + 子网 + 端口管理功能。1 y& J% a- B8 Y2 o* @" @
下面我给你完整规划 + 代码框架(基于你现有的 network_list_view 和 edit_network_view 结构,可直接嵌入项目)。
$ g% ]3 R0 m. ?; ]
( f7 u1 C" F% _2 K5 i2 O2 V; [( J: o
一、总体架构设计$ P/ h7 d9 z: G% x

% ]3 W) G  H% X我们按功能模块划分成三个部分:
0 d& f. o6 m5 h; x. I9 W1 ~# J* l8 l% Y( w4 h
networks/
  v; C2 K5 j6 Z9 m├── views/1 i9 N+ V$ v8 A. v; J9 d' N0 p
│   ├── networks.py     # 网络的增删改查
3 A% R0 z" Z0 O- k6 _# i+ W! n│   ├── subnets.py      # 子网管理(新增/编辑/删除)4 o0 |% u& ?. J7 n$ ~+ i7 H! v% z
│   ├── ports.py        # 端口管理(创建/删除/绑定安全组/绑定虚机)
, N# u" w; u! _- x- I) i: `* Y# C6 d, @2 b
├── templates/
, j  c' B5 ?) `. A│   ├── networks.html9 x* F0 ?% i( s
│   ├── network_edit.html( Z2 E; H3 ^! f0 }& R
│   ├── subnets.html
1 }1 c: }  |# J; A; h. t│   ├── subnet_edit.html& d3 b5 n, R/ c; W
│   ├── ports.html( D+ D7 k4 Y$ X6 D( W
│   ├── port_edit.html
! ]% [4 Y" ]% ^" F; S9 A
  M! |9 ?- A& Q└── urls.py             # 统一注册URL
5 }. ~( f- k7 v" L$ Y
9 Q6 f' M0 e  |* m& M( v% C 二、子网管理 Subnets 功能8 A8 Y0 J: }" e3 U/ j2 f
子网列表+ F, `) V4 \$ ]& [
# views/subnets.py
& U0 O8 }( F4 U9 Oimport requests/ y% Q! I$ d) B) X9 @) W. ]1 h* J
from django.shortcuts import render, redirect) v7 e, R& y" J* `
from django.contrib import messages1 H. {- b+ E7 Q, x  i1 Q" R# ]; W
from django.views.decorators.csrf import csrf_exempt" @) c' T1 D, F5 F

" ?7 p. U6 P" P# B) r@csrf_exempt- u1 r8 m1 p- D3 f  ]- n- z
def subnet_list_view(request, network_id):
" u. u& ?7 e" b: t4 Y0 ]: f7 h" p    """查看指定网络的所有子网"""2 q* i/ m8 V7 j. h; b
    token = request.session.get("token")# L9 m& F- x1 r4 R1 Q8 f# }
    headers = {"X-Auth-Token": token}3 N) G6 c9 L+ ^+ k
    resp = requests.get(f"{Neutron_Base}/subnets", headers=headers, timeout=10)
6 H, ~: Q) p& q8 v. ]0 I
4 N: `* D2 {# L! n, @    if resp.status_code == 200:
* I' I2 t6 i8 H5 Y- t0 z3 g& e        all_subnets = resp.json().get("subnets", [])
- q0 u* `, e1 B, c6 x0 f+ E        subnets = [s for s in all_subnets if s["network_id"] == network_id]
: Y2 ^# h( `: U% x: f: g- W" w. E/ C    else:; I) F9 R" w: ]
        messages.error(request, f"无法获取子网列表: {resp.text}")6 G) h4 J, Q/ h4 e7 F
        subnets = [], O3 G3 w& t- i: A8 r0 g, m

1 h1 H) G: h2 T' l    return render(request, "subnets.html", {"subnets": subnets, "network_id": network_id})
7 q+ V) b8 e0 j7 Z1 h8 V4 r2 D" s8 o. ]3 A
新建子网! }) r: ]" n7 @. [" Y, P
@csrf_exempt
- x' j" ?$ u- B% Kdef subnet_create_view(request, network_id):
! @& ^% Y& ?" _# w3 \# x1 D    if request.method == "POST":& O/ s4 ?) ]8 r$ A( B
        token = request.session.get("token")  l* Z( A2 m+ L( S, X
        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
9 u; V! d" l; h
: c( U# U+ t: M! }  @7 ?. m; ?        name = request.POST.get("name")
! S5 w  b5 a. {        cidr = request.POST.get("cidr"). S1 u! g3 |# a, }' t0 U) c
        gateway_ip = request.POST.get("gateway_ip")- A5 `8 n& `: t# ?. T
        enable_dhcp = request.POST.get("enable_dhcp") == "on": n6 d: e( T% K+ S: T

$ |* T( E$ e. U        data = {
  N+ O- H6 j& N/ D. m: ^( n, @            "subnet": {
  _+ r' S5 I$ N4 J/ ^                "network_id": network_id,0 b! z6 o1 ?% n, X; x, C0 F- H
                "ip_version": 4,
& J/ q3 @* R: F4 a                "cidr": cidr,0 k# {4 v0 T1 g
                "gateway_ip": gateway_ip,
3 n) o1 Q! J' E& k" e                "enable_dhcp": enable_dhcp,* D, M5 \  D. d
                "name": name,
6 c# d& A! l8 S) d$ }  i            }
" K" K4 m# d8 B  s        }
4 A+ M% ]& w5 d0 ~, W# [: Z( w7 @7 Z6 k' K9 v) w
        resp = requests.post(f"{Neutron_Base}/subnets", headers=headers, json=data, timeout=15)
: L3 l$ X. b1 ~1 M+ v: ~        if resp.status_code in [200, 201]:
( o; D7 d6 G: U& s( Y9 z4 `            messages.success(request, "子网创建成功")* A" s) h7 C3 \3 ^
        else:
3 j5 d" S; T: H            messages.error(request, f"子网创建失败: {resp.text}")
( ]- {6 d! o/ S* n        return redirect("subnet_list", network_id=network_id)
) G. H7 V" h8 a/ L4 X) J' P
0 q) b/ }! u6 o( J    return render(request, "subnet_edit.html", {"network_id": network_id})7 G, L2 Q. B" v% S6 D1 T
9 |9 i7 s; q  m$ E& b9 A0 M
删除子网
$ _. Z1 g8 @$ Z$ _9 qdef subnet_delete_view(request, subnet_id, network_id):
8 H) w, E, T+ N* o    token = request.session.get("token")- C1 R6 {8 q( ]6 c% q: u) J2 @3 v: |8 K
    headers = {"X-Auth-Token": token}
1 m0 N; z& z1 Z1 F& |  Z' F: W    resp = requests.delete(f"{Neutron_Base}/subnets/{subnet_id}", headers=headers, timeout=10)
: Q) P" b& x3 j9 z6 g$ y7 m
# Z1 u3 i" |, }& B( @    if resp.status_code == 204:
) [' [5 n& g5 F0 x  b        messages.success(request, "子网已删除")4 y' g; I& b' Z+ x
    else:
1 ~% t' R- q4 T% @, ]% q        messages.error(request, f"删除失败: {resp.text}")% Q# x  @8 a; c: X3 C5 n: p* V5 ~
    return redirect("subnet_list", network_id=network_id)
7 F. ~3 g$ @' F" v, _
( d' c4 l7 q8 l4 ^ 三、端口 Ports 管理
7 a8 L' _4 A$ r. g- `% [3 s2 x端口列表5 v; T" B8 [! W8 q& [
def port_list_view(request, network_id):) q* c4 h7 Y8 d- b
    token = request.session.get("token")( ~& _8 r( k" o0 U" \9 q4 E8 {
    headers = {"X-Auth-Token": token}
- Z% v' Z; d1 c    resp = requests.get(f"{Neutron_Base}/ports", headers=headers, timeout=10)- V$ d1 c" i' U

, R6 {* ~; @/ g! Q6 V    if resp.status_code == 200:5 t3 _/ I8 O  W7 {( C
        ports = [p for p in resp.json().get("ports", []) if p["network_id"] == network_id]
5 q" p7 ]  n; T$ l; a) j. i3 @    else:
7 A# W9 _( e" Q) M  D9 z' ^# t+ g7 L        ports = [], o  @6 B. \/ t8 j9 l
        messages.error(request, f"无法获取端口: {resp.text}")0 s$ n# F- Z9 k; I" a1 D

8 V1 A' g+ w5 ], d6 b/ C" f    return render(request, "ports.html", {"ports": ports, "network_id": network_id})- A+ K% P5 c! e3 ~
6 j9 i! [* w1 i" J8 Q  c  K  [0 z0 p
新建端口
6 V/ l, N, J  t@csrf_exempt
4 X7 C2 L0 E; U1 V5 e: ]def port_create_view(request, network_id):, S  j$ _1 T* v
    if request.method == "POST":
. U% ?+ ~0 ?/ h6 a3 _3 b; t" H        token = request.session.get("token")* z( h  y1 H' Y$ p# o( B% i" q
        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
: k" p: I. \! {) a0 w; M: _& B3 ]8 Z- C
        name = request.POST.get("name")9 v' V! |1 z/ @, C" {! W
        data = {% G0 H! W4 X5 y0 I( G3 A
            "port": {
* G2 [, W5 @1 L1 Z: Q7 \                "network_id": network_id,) u4 @& e8 P5 X3 j! r6 Y1 a
                "name": name,/ L; i1 Q, n4 {
                "admin_state_up": True) i# Z, L2 U2 t2 z9 y
            }9 r9 L3 {: f! g" [( }
        }  j3 i7 I' G# }! B
        resp = requests.post(f"{Neutron_Base}/ports", headers=headers, json=data, timeout=10)
- M* I- e9 N) }7 E+ B2 q+ A        if resp.status_code in [200, 201]:
& R/ J: j) I, ?6 d            messages.success(request, "端口创建成功")) X" J) N& o( v+ ?# N3 E& |
        else:
- ~; A4 Z  v5 k7 ]; {( D# L+ t2 Q            messages.error(request, f"创建失败: {resp.text}")' e5 Y# V/ o: R) v1 s
        return redirect("port_list", network_id=network_id)2 O! u: b# m& D- B8 C1 ^

' T/ K4 ^" W+ E9 C; n3 H9 H+ w% r: u$ n    return render(request, "port_edit.html", {"network_id": network_id})
5 R$ S# ^: O, K# u0 `. _7 y: ~& I4 t( T, p5 F2 C
删除端口' \! I$ O6 h" D( Z3 e0 }
def port_delete_view(request, port_id, network_id):# I# m, t6 v2 j* V# _
    token = request.session.get("token")
- }: r# f5 v  s3 _) Z% N- C0 h6 b    headers = {"X-Auth-Token": token}& r8 b' t  c& z3 ~- m* Y8 H
    resp = requests.delete(f"{Neutron_Base}/ports/{port_id}", headers=headers, timeout=10)2 t% S/ j0 U( v* \; X1 T
. _9 r, a: T% v4 v! B7 F
    if resp.status_code == 204:3 J3 l5 T5 w: z0 W# ?
        messages.success(request, "端口已删除")% M8 @; q! m  X! L. j$ R+ T
    else:8 [$ k9 m9 p$ h" j4 N
        messages.error(request, f"删除失败: {resp.text}")6 B2 b  _7 ]: r) d# ]+ F' h( k: U

- O7 ~3 }0 Q+ d) R  C; J    return redirect("port_list", network_id=network_id)
" c; o; M0 Y4 ]  L1 G! _' R
/ S5 d3 q/ t* N6 d) m6 s4️⃣ 更新安全组绑定
9 `2 r6 Q; O- S; a1 o@csrf_exempt! o% z/ Y5 `) {/ A: S
def port_update_sg_view(request, port_id, network_id):0 x5 n1 T, a8 Q  Q6 y3 F8 R+ h  ]; g- @) _
    if request.method == "POST":- w1 `* X6 u' [6 E. s2 i
        token = request.session.get("token")
5 U* [. a1 p+ s& V  A  W8 ^" \; T* A        headers = {"X-Auth-Token": token, "Content-Type": "application/json"}# {& P4 }' ]' }, d
        sg_id = request.POST.get("security_group_id")
6 J' D# {; M4 m  C% W  B7 W7 g# u6 G7 R( h7 s' O5 @
        data = {"port": {"security_groups": [sg_id]}}0 g) o% P4 m7 d  H4 e- Z
        resp = requests.put(f"{Neutron_Base}/ports/{port_id}", headers=headers, json=data, timeout=10)
, k' u( S5 |. R% _& j
) v, I/ Q2 c6 ?& q        if resp.status_code in [200, 202]:
# ?; Y& O% U$ k            messages.success(request, "安全组更新成功")
0 l6 P, r# c% E8 M        else:
! U. g9 _/ B+ @' C+ k3 H4 c            messages.error(request, f"安全组更新失败: {resp.text}")3 W) P# L+ I4 H0 E
! X7 D* q; y" }7 W* Q
    return redirect("port_list", network_id=network_id)
4 |7 m$ A6 D. [, I$ u1 B
/ T! l) O1 I6 ?3 P. Y4 j绑定虚机(实例)接口2 C9 A) K/ ~1 v1 M! p; ]
@csrf_exempt
& Z8 L/ R, z) F$ i. j# Sdef port_bind_instance_view(request, port_id, server_id, network_id):
; ?5 c9 V7 Y0 \& J1 }1 U    token = request.session.get("token")
9 j* h/ I4 a. @4 {% x    headers = {"X-Auth-Token": token, "Content-Type": "application/json"}! U  l7 |: W6 ]; D% S1 \* c

. o1 M4 R- o/ B) x3 p7 b    data = {
7 f9 M  o( G) `7 p2 r8 ]. [) y        "port": {
# p  T0 S; S* p( ^) i            "device_id": server_id,
! V# G. A8 Z! r$ u; z! Y7 m            "device_owner": "compute:nova"1 C2 g$ ~1 T; f$ {
        }: x2 c) z. U+ B7 q& Q6 F  U! N. O
    }
+ f, G- c: e" W* z9 y6 I( g  b0 Z& b- c: D/ N7 G( l
    resp = requests.put(f"{Neutron_Base}/ports/{port_id}", headers=headers, json=data, timeout=10)
" a- W  m* H, e. T' k3 d3 b    if resp.status_code in [200, 202]:
7 x# H& o3 z7 v" s2 {9 O        messages.success(request, "端口成功绑定到虚机")
/ m0 u- o- q2 {% W$ v8 M    else:
) ?, p) ?/ P4 r' ~& p0 A$ l        messages.error(request, f"绑定失败: {resp.text}")
" {0 N. \7 V; t# t" V' |    return redirect("port_list", network_id=network_id)3 Q! M# u0 V1 K5 m5 O2 g8 [/ D

8 h6 |- ~7 ~+ L7 } 四、URL 路由示例  C. o/ J5 [7 g! a. @
# urls.py
' s* a5 e6 N0 r% ^% mfrom django.urls import path
% y* Y7 N3 I$ E& Tfrom .views import networks, subnets, ports6 d( k# c; Z" k: v( n. \

  J3 _% X" _2 a+ ?6 A9 q  Q7 Kurlpatterns = [
, A9 b0 O7 |$ q! W    path("networks/", networks.network_list_view, name="networks"),
9 u+ s+ u0 ^' x7 r: c) W    path("networks/edit/<str:network_id>/", networks.edit_network_view, name="edit_network"),
; F! B- C. |& a! q1 F3 K# s/ W2 K# |) ]
    path("networks/<str:network_id>/subnets/", subnets.subnet_list_view, name="subnet_list"),# Q* H3 ]) m7 c- }9 W) ^
    path("networks/<str:network_id>/subnets/create/", subnets.subnet_create_view, name="subnet_create"),7 w9 N' N$ p; [" X- k
    path("networks/<str:network_id>/subnets/delete/<str:subnet_id>/", subnets.subnet_delete_view, name="subnet_delete"),6 ~( s5 p% u! A+ k7 U2 P4 Y& N. Y3 y
9 [2 B$ `$ L: I. U
    path("networks/<str:network_id>/ports/", ports.port_list_view, name="port_list"),* e; J( t# E- A" W1 p
    path("networks/<str:network_id>/ports/create/", ports.port_create_view, name="port_create"),
; g6 y% a+ l7 j! V2 F. D$ K    path("networks/<str:network_id>/ports/delete/<str:port_id>/", ports.port_delete_view, name="port_delete"),( J  F- k4 Q- j$ S! V9 w0 B
    path("networks/<str:network_id>/ports/update_sg/<str:port_id>/", ports.port_update_sg_view, name="port_update_sg"),
" F5 A: j+ x5 m    path("networks/<str:network_id>/ports/bind/<str:port_id>/<str:server_id>/", ports.port_bind_instance_view, name="port_bind_instance"),
7 W& k: ]( S  f. @, w3 `]
" k* N4 @8 B4 N
7 R) {7 t, h" x9 C8 u: ~0 u$ x2 P7 K
您需要登录后才可以回帖 登录 | 注册

本版积分规则

返回首页|Archiver|手机版|小黑屋|易陆发现技术论坛 ( 蜀ICP备2026014127号-1 )

GMT+8, 2026-6-12 01:11 , Processed in 0.149959 second(s), 22 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表